วิธีการรันงาน cron ภายในคอนเทนเนอร์นักเทียบท่า?


275

ฉันพยายามเรียกใช้ cronjob ภายในคอนเทนเนอร์ docker ที่เรียกใช้เชลล์สคริปต์

เมื่อวานนี้ฉันค้นหาทั่วทั้งเว็บและล้นสแต็ก แต่ฉันหาโซลูชันที่ใช้งานไม่ได้จริงๆ
ฉันจะทำสิ่งนี้ได้อย่างไร

แก้ไข:

ฉันได้สร้างที่เก็บ github (แสดงความคิดเห็น)กับคอนเทนเนอร์ cron นักเทียบท่าที่ใช้งานได้ซึ่งเรียกใช้เชลล์สคริปต์ในช่วงเวลาที่กำหนด

คำตอบ:


365

คุณสามารถคัดลอก crontab ของคุณไปยังรูปภาพเพื่อให้คอนเทนเนอร์เปิดใช้จากอิมเมจดังกล่าวเพื่อรันงาน

ดู " ทำงาน cron กับ Docker " จากJulien BoulayในเขาEkito/docker-cron:

มาสร้างไฟล์ใหม่ที่ชื่อว่า " hello-cron" เพื่ออธิบายงานของเรา

* * * * * echo "Hello world" >> /var/log/cron.log 2>&1
# An empty line is required at the end of this file for a valid cron file.

Dockerfile ต่อไปนี้อธิบายขั้นตอนทั้งหมดในการสร้างภาพของคุณ

FROM ubuntu:latest
MAINTAINER docker@ekito.fr

RUN apt-get update && apt-get -y install cron

# Copy hello-cron file to the cron.d directory
COPY hello-cron /etc/cron.d/hello-cron

# Give execution rights on the cron job
RUN chmod 0644 /etc/cron.d/hello-cron

# Apply cron job
RUN crontab /etc/cron.d/hello-cron

# Create the log file to be able to run tail
RUN touch /var/log/cron.log

# Run the command on container startup
CMD cron && tail -f /var/log/cron.log

(ดูความคิดเห็นของGaafarและฉันจะทำให้มีเสียงดังน้อยลงได้อย่างไร : สามารถทำงานได้เช่นกัน)apt-get
apt-get -y install -qq --force-yes cron

ตามที่ระบุไว้โดยNathan Lloydในความคิดเห็น :

ทราบอย่างรวดเร็วเกี่ยวกับ gotcha A:
หากคุณกำลังเพิ่มไฟล์สคริปต์และบอก cron เพื่อให้ทำงานได้อย่าลืมCron ล้มเหลวอย่างเงียบ ๆ หากคุณลืม
RUN chmod 0744 /the_script


หรือให้แน่ใจว่างานของคุณเปลี่ยนเส้นทางโดยตรงไปยัง stdout / stderr แทนที่จะเป็นไฟล์บันทึกตามที่อธิบายไว้ในคำตอบของhugoShaka :

 * * * * * root echo hello > /proc/1/fd/1 2>/proc/1/fd/2

แทนที่บรรทัด Dockerfile ล่าสุดด้วย

CMD ["cron", "-f"]

ดูเพิ่มเติม (เกี่ยวกับcron -fซึ่งจะบอกว่า cron "เบื้องหน้า") " docker ubuntu cron -fไม่ทำงาน "


สร้างและเรียกใช้:

sudo docker build --rm -t ekito/cron-example .
sudo docker run -t -i ekito/cron-example

อดทนรอ 2 นาทีและ commandline ของคุณควรแสดง:

Hello world
Hello world

Ericเพิ่มในความคิดเห็น :

โปรดทราบว่าtailอาจไม่แสดงไฟล์ที่ถูกต้องหากมันถูกสร้างขึ้นในระหว่างการสร้างอิมเมจ
หากเป็นกรณีนี้คุณต้องสร้างหรือแตะที่ไฟล์ระหว่างที่รันไทม์ของคอนเทนเนอร์เพื่อให้หางหยิบไฟล์ที่ถูกต้อง

โปรดดู " ผลลัพธ์tail -fที่ด้านท้ายของนักเทียบท่าCMDไม่แสดง "


1
ฉันต้องติดตั้ง cron ก่อนเพราะมันไม่รวม แต่ด้วยการเพิ่มสิ่งนี้ลงใน Dockerfile มันทำงานได้ ขอบคุณ! RUN apt-get update && apt-get install cron
C Heyer

2
คุณควรเพิ่ม-yการติดตั้ง cron เพื่อหลีกเลี่ยงการออกจาก
docker build

1
@Gaafar ถูกต้อง! ฉันได้รวมความคิดเห็นของคุณไว้ในคำตอบเพื่อให้มองเห็นได้มากขึ้นและเพิ่มตัวเลือกอื่น
VonC

6
โซลูชันนี้ยังใช้งานได้หรือไม่ เมื่อฉันทำตามแนวทางที่กำหนดเมื่อฉันเข้าสู่ระบบในฐานะที่เป็นรูทและประเภทcrontab -lฉันได้รับNo crontab ติดตั้งสำหรับรูทเช่นกันหน้าจอของฉันยังว่างเปล่า อย่างไรก็ตามเมื่อฉันตรวจสอบ '/etc/cron.d/' ฉันเห็น crontab fiel อยู่ที่นั่น (และน่าประหลาดใจมากขึ้น) เมื่อฉันตรวจสอบ/var/log/cron.logฉันเห็นว่าสคริปต์กำลังทำงานอยู่ (เนื้อหาของไฟล์จะถูกผนวกเข้าด้วยHello World) ฉันดึงภาพนี้ใน Dockerfile FROM phusion/baseimage:0.10.0ฉัน: ความคิดใด ๆ เกี่ยวกับความแตกต่างในพฤติกรรม?
Homunculus Reticulli

11
ตั้งแต่ปีพ. ศ. 2561 วิธีนี้ใช้ไม่ได้อีกต่อไป มีใครสามารถรับ cronjob ของพวกเขาที่จะทำงานกับ Ubuntu เป็นภาพฐานหรือไม่ ฉันไม่สนใจภาพอัลไพน์ที่มาพร้อมกับ cron วิ่งออกจากกล่อง
นกกระทุง

147

วิธีการแก้ปัญหาที่นำมาใช้อาจเป็นอันตรายในระบบการผลิต

ในนักเทียบท่าคุณควรดำเนินการหนึ่งกระบวนการต่อคอนเทนเนอร์หนึ่งเดียวเพราะหากคุณไม่ทำกระบวนการที่แยกและไปที่พื้นหลังจะไม่ได้รับการตรวจสอบและอาจหยุดทำงานโดยที่คุณไม่รู้ตัว

เมื่อคุณใช้CMD cron && tail -f /var/log/cron.logกระบวนการ cron โดยทั่วไปจะแยกเพื่อดำเนินการcronในพื้นหลังกระบวนการหลักจะออกและให้คุณดำเนินการtailfในเบื้องหน้า กระบวนการ cron พื้นหลังสามารถหยุดหรือล้มเหลวคุณจะไม่สังเกตเห็นคอนเทนเนอร์ของคุณจะยังคงทำงานอย่างเงียบ ๆ และเครื่องมือ orchestration ของคุณจะไม่รีสตาร์ท

คุณสามารถหลีกเลี่ยงสิ่งที่ดังกล่าวโดยการเปลี่ยนเส้นทางโดยตรงคำสั่ง cron ของการส่งออกลงในนักเทียบท่าของคุณstdoutและstderrที่ตั้งอยู่ตามลำดับในและ/proc/1/fd/1/proc/1/fd/2

การใช้การเปลี่ยนเส้นทางเชลล์พื้นฐานคุณอาจต้องการทำสิ่งนี้:

* * * * * root echo hello > /proc/1/fd/1 2>/proc/1/fd/2

และ CMD ของคุณจะเป็น: CMD ["cron", "-f"]


14
Nice: cron -fสำหรับ "พื้นหน้า cron" ฉันได้รวมคำตอบของคุณไว้ในรายการด้านบนเพื่อความชัดเจน +1
VonC

สมมติว่าโปรแกรมของฉันไม่ส่งออกอะไร ฉันยังสามารถใช้วิธีนี้และมั่นใจได้ว่ากระบวนการของฉันจะไม่หยุดทำงานในเบื้องหลังหรือไม่
Arcsector

1
@Acscs วิธีการนี้หลีกเลี่ยงการวางกระบวนการในพื้นหลังที่ว่าทำไมมันไม่ได้ล้มเหลวอย่างเงียบ ๆ มีกระบวนการพื้นหลังในคอนเทนเนอร์นักเทียบท่าไม่ใช่เรื่องง่าย หากคุณต้องการมีกระบวนการพื้นหลังที่กำลังทำงานอยู่คุณอาจต้องการใช้กระบวนการเริ่มต้นเพื่อตรวจสอบกระบวนการหลายอย่างที่คุณเรียกใช้ในคอนเทนเนอร์ อีกวิธีหนึ่งคือการเริ่มต้นกระบวนการในภาชนะอื่นถัดจากหลักที่เรียกว่า 'sidecar' วิธีที่ดีที่สุดคือการหลีกเลี่ยงกระบวนการหลายอย่างในคอนเทนเนอร์
hugoShaka

ดีและสะอาด! รักเลย :)
AmaelH

1
นี่เป็นทางออกที่ดีและทำงานได้ดีสำหรับเรานอกเหนือจากปัญหาเดียว เมื่อคอนเทนเนอร์ได้รับสัญญาณ SIGTERM ดูเหมือนว่าจะไม่รอให้กระบวนการตามกำหนดเวลาเสร็จสิ้นและปิดเครื่องอย่างสวยงาม แต่เป็นการฆ่ากระบวนการซึ่งอาจทำให้เกิดปัญหา
James Hulse

107

สำหรับผู้ที่ต้องการใช้ภาพที่เรียบง่ายและมีน้ำหนักเบา:

FROM alpine:3.6

# copy crontabs for root user
COPY config/cronjobs /etc/crontabs/root

# start crond with log level 8 in foreground, output to stderr
CMD ["crond", "-f", "-d", "8"]

โดยที่cronjobsเป็นไฟล์ที่มี cronjobs ของคุณในรูปแบบนี้:

* * * * * echo "hello stackoverflow" >> /test_file 2>&1
# remember to end this file with an empty new line

10
ภาพที่เรียบง่ายน้ำหนักเบาและมาตรฐาน นี่ควรเป็นคำตอบที่ยอมรับได้ ใช้การ> /proc/1/fd/1 2> /proc/1/fd/2เปลี่ยนเส้นทางเพื่อเข้าถึงเอาต์พุต cronjobs โดยตรงจากบันทึกนักเทียบท่า
HenriTel

2
สำหรับผู้ที่ไม่ได้ใช้อัลไพน์: crond ที่สนับสนุน-d 8พารามิเตอร์ไม่ใช่ cron มาตรฐานมันเป็นคำสั่ง crond จาก busybox busybox crond -f -d 8ยกตัวอย่างเช่นจากอูบุนตูคุณสามารถทำงานนี้เป็น -L /dev/stdout/สำหรับรุ่นเก่าที่คุณต้องใช้
Trendfischer

2
ฉันจะให้ +100 ถ้าทำได้ นี่เป็นวิธีที่ดีที่สุดในการรันงาน cron ในสภาพแวดล้อม Docker
Jitsusama

1
หากคุณไม่ต้องการสร้างภาพใหม่ทุกครั้งที่คุณเปลี่ยนงาน cron (หรือหากคุณต้องการหลายภาพ) คุณสามารถเรียกใช้ Alpine และใช้วอลลุ่มเพื่อตั้งค่า cron ฉันทดสอบมันโดยใช้สิ่งต่อไปนี้: docker run -v ${PWD}/cronjobs:/etc/crontabs/root alpine:3.6 crond -f -d 8. @Gostostav คุณสามารถใช้สิ่งที่คล้ายกันใน Docker Compose
duality_

1
CMD ["crond"หรือCMD ["cron"?
codesmith

38

สิ่งที่ @VonC แนะนำคือดี แต่ฉันชอบทำการกำหนดค่างาน cron ทั้งหมดในบรรทัดเดียว สิ่งนี้จะหลีกเลี่ยงปัญหาข้ามแพลตฟอร์มเช่นตำแหน่ง cronjob และคุณไม่ต้องการไฟล์ cron แยกกัน

FROM ubuntu:latest

# Install cron
RUN apt-get -y install cron

# Create the log file to be able to run tail
RUN touch /var/log/cron.log

# Setup cron job
RUN (crontab -l ; echo "* * * * * echo "Hello world" >> /var/log/cron.log") | crontab

# Run the command on container startup
CMD cron && tail -f /var/log/cron.log

หลังจากเรียกใช้คอนเทนเนอร์นักเทียบท่าคุณสามารถตรวจสอบให้แน่ใจว่าบริการ cron ทำงานโดย:

# To check if the job is scheduled
docker exec -ti <your-container-id> bash -c "crontab -l"
# To check if the cron service is running
docker exec -ti <your-container-id> bash -c "pgrep cron"

หากคุณต้องการให้ ENTRYPOINT แทน CMD คุณสามารถทดแทน CMD ด้านบนด้วย

ENTRYPOINT cron start && tail -f /var/log/cron.log

1
ทางเลือกที่น่าสนใจ +1
VonC

2
RUN apt-get update && apt-get -y install cronมิฉะนั้นจะไม่สามารถหาแพ็คเกจได้cron
ตัวอักษร

2
ขอบคุณ Youness คุณทำให้ฉันมีความคิดในการทำต่อไปนี้ซึ่งทำงานในกรณีของฉันที่ cron แต่ละคนจะถูกระบุในไฟล์ที่แตกต่าง: RUN cat $APP_HOME/crons/* | crontab Like Charm :)
marcostvz

การเพิ่มcronสคริปต์จุดเข้าใช้งานดูเหมือนเป็นตัวเลือกที่ดีที่สุด: ENTRYPOINT ["entrypoint.sh"]
bozdoz

20

มีอีกวิธีที่จะทำคือใช้Taskerซึ่งเป็น task runner ที่รองรับ cron (a scheduler)

ทำไม บางครั้งเพื่อเรียกใช้งาน cron คุณต้องผสมอิมเมจพื้นฐานของคุณ (python, java, nodejs, ruby) ด้วย crond นั่นหมายถึงภาพอื่นที่จะรักษา ทาซเคอร์หลีกเลี่ยงสิ่งนั้นด้วยการแยกส่วนของ crond และ container คุณสามารถโฟกัสไปที่รูปภาพที่คุณต้องการเรียกใช้งานคำสั่งของคุณและกำหนดค่า Tasker ให้ใช้งานได้

นี่คือdocker-compose.ymlไฟล์ที่จะทำงานบางอย่างให้คุณ

version: "2"

services:
    tasker:
        image: strm/tasker
        volumes:
            - "/var/run/docker.sock:/var/run/docker.sock"
        environment:
            configuration: |
                logging:
                    level:
                        ROOT: WARN
                        org.springframework.web: WARN
                        sh.strm: DEBUG
                schedule:
                    - every: minute
                      task: hello
                    - every: minute
                      task: helloFromPython
                    - every: minute
                      task: helloFromNode
                tasks:
                    docker:
                        - name: hello
                          image: debian:jessie
                          script:
                              - echo Hello world from Tasker
                        - name: helloFromPython
                          image: python:3-slim
                          script:
                              - python -c 'print("Hello world from python")'
                        - name: helloFromNode
                          image: node:8
                          script:
                              - node -e 'console.log("Hello from node")'

มี 3 งานที่นั่นพวกเขาทั้งหมดจะทำงานทุกนาที ( every: minute) และแต่ละคนจะรันscriptโค้ดภายในภาพที่กำหนดไว้ในimageส่วน

เพียงแค่เรียกใช้docker-compose upและดูว่าใช้งานได้ นี่คือ Tasker repo ที่มีเอกสารฉบับเต็ม:

http://github.com/opsxcq/tasker


นักเทียบท่า (การเรียกใช้คอนเทนเนอร์นักเทียบท่าจากคอนเทนเนอร์อื่น) เป็นวิธีปฏิบัติที่ไม่ดีและควร จำกัด เฉพาะการรวมอย่างต่อเนื่อง วิธีแก้ปัญหาจะใช้docker execกับคอนเทนเนอร์ที่ระบุ
HenriTel

1
ทาซเคอร์ไม่ได้ใช้นักเทียบท่าในนักเทียบท่า (Dind / Dockerception) โปรดทราบว่าจะถูกส่งผ่านซ็อกเก็ตนักเทียบท่าเป็นการจับคู่ภาชนะที่วางทั้งหมดจะถูกวางใน daemon ที่ tasker ทำงาน และหากคุณไม่ต้องการเรียกใช้ tasker ภายในนักเทียบท่าคุณสามารถปรับใช้เป็นแอปพลิเคชันอื่น ๆ ได้
OPSXCQ

1
ฉันไม่ได้รับประโยชน์จากการใช้ tasker ดูเหมือน overkill จริง ๆ กับฉันโดยใช้ java และ sh *** เพียงเพื่อเรียกใช้งาน cron
Karl Adler

การผสม cron และอิมเมจพื้นฐานที่คุณต้องการ (เช่นไพ ธ อน / โหนด) สร้างการพึ่งพาพิเศษที่จำเป็นต้องได้รับการดูแลและปรับใช้ในสถานการณ์สมมตินี้งานทั้งหมดแชร์ภาชนะเดียวกันหมายความว่าคุณต้องกังวลเกี่ยวกับการล้างทุกอย่างหลังจาก ทุกงานวิ่ง งานที่ทำงานใน tasker นั้นเป็น idempotent ดังนั้นคุณมีสิ่งที่ต้องกังวลน้อยลง
OPSXCQ

13

คำตอบของ VonCค่อนข้างละเอียด นอกจากนี้ฉันต้องการเพิ่มสิ่งหนึ่งที่ช่วยฉัน หากคุณเพียงแค่ต้องการรันงาน cron โดยไม่ทำการตัดไฟล์คุณจะถูกลบออก&& tail -f /var/log/cron.logจากคำสั่ง cron

อย่างไรก็ตามสิ่งนี้จะทำให้คอนเทนเนอร์ Docker ออกไม่นานหลังจากที่ทำงานเนื่องจากเมื่อคำสั่ง cron เสร็จสมบูรณ์ Docker คิดว่าคำสั่งสุดท้ายได้ออกจากแล้วจึงฆ่าคอนเทนเนอร์ นี้สามารถหลีกเลี่ยงได้โดยการเรียกใช้ cron cron -fในเบื้องหน้าผ่าน


9

แม้ว่านี่จะมีจุดมุ่งหมายเพื่อให้ทำงานนอกกระบวนการที่กำลังทำงานอยู่ในคอนเทนเนอร์ผ่านทางexecส่วนต่อประสานของ Docker แต่สิ่งนี้อาจเป็นที่สนใจของคุณ

ฉันเขียนดีมอนที่สังเกตงานบรรจุภัณฑ์และกำหนดเวลางานที่กำหนดไว้ในข้อมูลเมตาของพวกเขา ตัวอย่าง:

version: '2'

services:
  wordpress:
    image: wordpress
  mysql:
    image: mariadb
    volumes:
      - ./database_dumps:/dumps
    labels:
      deck-chores.dump.command: sh -c "mysqldump --all-databases > /dumps/dump-$$(date -Idate)"
      deck-chores.dump.interval: daily

'คลาสสิก' สามารถกำหนดค่าคล้าย cron ได้

นี่เป็นเอกสารที่นี่เป็นที่เก็บภาพ


ขอบคุณ. คำตอบนี้เหมาะสมที่สุดสำหรับสภาพแวดล้อมของคอนเทนเนอร์ Docker ไม่มีการเปลี่ยนแปลงใด ๆ ในอิมเมจ Docker เพียงเพิ่มคอนเทนเนอร์พิเศษสำหรับการดำเนินงานมันทำงานเหมือนคำสั่งdocker exec <container_name> <some_command>ตามกำหนดเวลา
PRIHLOP

นี่เป็นคำตอบที่ "ง่ายที่สุด" ที่เรียบง่ายที่สุด
อิบราฮิม Awad

9

ฉันสร้างอิมเมจ Docker ตามคำตอบอื่น ๆ ซึ่งสามารถใช้ได้

docker run -v "/path/to/cron:/etc/cron.d/crontab" gaafar/cron

โดยที่/path/to/cron: พา ธ สัมบูรณ์ไปยังไฟล์ crontab หรือคุณสามารถใช้เป็นฐานใน Dockerfile:

FROM gaafar/cron

# COPY crontab file in the cron directory
COPY crontab /etc/cron.d/crontab

# Add your commands here

สำหรับการอ้างอิงของภาพอยู่ที่นี่


ภาพที่น่าสนใจ +1
VonC

5

เมื่อคุณปรับใช้คอนเทนเนอร์ของคุณบนโฮสต์อื่นเพียงสังเกตว่ามันจะไม่เริ่มกระบวนการใด ๆ โดยอัตโนมัติ คุณต้องตรวจสอบให้แน่ใจว่าบริการ 'cron' ทำงานอยู่ในคอนเทนเนอร์ของคุณ ในกรณีของเราฉันกำลังใช้ Supervisord กับบริการอื่น ๆ เพื่อเริ่มบริการ cron

[program:misc]
command=/etc/init.d/cron restart
user=root
autostart=true
autorestart=true
stderr_logfile=/var/log/misc-cron.err.log
stdout_logfile=/var/log/misc-cron.out.log
priority=998

ฉันพบข้อผิดพลาดใน supervisor.log ว่าบริการ cron หยุดทำงานหลายครั้งและเข้าสู่สถานะ FATAL อย่างไรก็ตาม cron ดูเหมือนว่าจะทำงานด้านบนและดำเนิน cronjobs ตามปกติ ขอบคุณสำหรับสิ่งนี้!
lephleg

ใช่สิ่งเดียวกันก็เกิดขึ้นกับฉันเช่นกัน แต่ก็ใช้งานได้ตามปกติดังนั้นไม่จำเป็นต้องกังวล
Sagar Ghuge

5

กำหนด cronjob ในคอนเทนเนอร์เฉพาะที่รันคำสั่งผ่านนักเทียบท่า exec กับบริการของคุณ

นี่คือการเชื่อมโยงที่สูงขึ้นและสคริปต์การเรียกใช้จะสามารถเข้าถึงตัวแปรสภาพแวดล้อมที่คุณกำหนดไว้สำหรับบริการของคุณ

#docker-compose.yml
version: "3.3"
services:
    myservice:
      environment:
        MSG: i'm being cronjobbed, every minute!
      image: alpine
      container_name: myservice
      command: tail -f /dev/null

    cronjobber:
     image: docker:edge
     volumes:
      - /var/run/docker.sock:/var/run/docker.sock
     container_name: cronjobber
     command: >
          sh -c "
          echo '* * * * * docker exec myservice printenv | grep MSG' > /etc/crontabs/root
          && crond -f"

ฉันไม่สามารถใช้งานสิ่งนี้ได้โดยใช้นักเทียบท่า รับmyservice unknownข้อผิดพลาด
Mark Grimes

ควรจะมีคำเตือนเกี่ยวกับผลกระทบต่อความปลอดภัยสูงในการติดตั้งซ็อกเก็ตนักเทียบท่ามี: lvh.io/posts/...
สบาย ๆ

4

หากคุณใช้นักเทียบท่าสำหรับ windows โปรดจำไว้ว่าคุณต้องเปลี่ยนรูปแบบสิ้นสุดบรรทัดจาก CRLF เป็น LF (เช่นจาก dos เป็น unix) หากคุณต้องการนำเข้าไฟล์ crontab จาก windows ไปยังคอนเทนเนอร์ ubuntu ของคุณ ถ้าไม่ทำงาน cron ของคุณจะไม่ทำงาน นี่คือตัวอย่างการทำงาน:

FROM ubuntu:latest

RUN apt-get update && apt-get -y install cron
RUN apt-get update && apt-get install -y dos2unix

# Add crontab file (from your windows host) to the cron directory
ADD cron/hello-cron /etc/cron.d/hello-cron

# Change line ending format to LF
RUN dos2unix /etc/cron.d/hello-cron

# Give execution rights on the cron job
RUN chmod 0644 /etc/cron.d/hello-cron

# Apply cron job
RUN crontab /etc/cron.d/hello-cron

# Create the log file to be able to run tail
RUN touch /var/log/hello-cron.log

# Run the command on container startup
CMD cron && tail -f /var/log/hello-cron.log

ที่จริงฉันใช้เวลาหลายชั่วโมงในการคิดออกเพราะการดีบั๊กงาน cron ในตู้เทียบท่าเป็นงานที่น่าเบื่อ หวังว่ามันจะช่วยให้คนอื่นที่นั่นไม่สามารถใช้รหัสได้


3

จากตัวอย่างด้านบนฉันสร้างชุดค่าผสมนี้:

รูปภาพอัลไพน์และแก้ไขโดยใช้ Crontab ในนาโน (ฉันเกลียด vi)

FROM alpine

RUN apk update
RUN apk add curl nano

ENV EDITOR=/usr/bin/nano 

# start crond with log level 8 in foreground, output to stderr
CMD ["crond", "-f", "-d", "8"]

# Shell Access
# docker exec -it <CONTAINERID> /bin/sh

# Example Cron Entry
# crontab -e
# * * * * * echo hello > /proc/1/fd/1 2>/proc/1/fd/2
# DATE/TIME WILL BE IN UTC

2

ติดตั้ง cron แบบขนานกับงานขาจร

สร้างไฟล์สคริปต์เรียกใช้ run.sh โดยมีงานที่ควรรันเป็นระยะ

#!/bin/bash
timestamp=`date +%Y/%m/%d-%H:%M:%S`
echo "System path is $PATH at $timestamp"

บันทึกและออก.

ใช้จุดเข้าใช้งานแทน CMD

หากคุณมีงานหลายอย่างที่จะต้องดำเนินการในระหว่างการจัดเก็บข้อมูลนักเทียบท่าใช้ไฟล์จุดเข้าใช้งานเพื่อเรียกใช้ได้

ไฟล์ Entrypoint เป็นไฟล์สคริปต์ที่เข้าสู่การทำงานเมื่อออกคำสั่งนักเรียกใช้งาน ดังนั้นขั้นตอนทั้งหมดที่เราต้องการเรียกใช้สามารถใส่ในไฟล์สคริปต์นี้

ตัวอย่างเช่นเรามี 2 งานให้ทำงาน:

เรียกใช้ครั้งเดียวงาน : echo“ เริ่มต้นคอนเทนเนอร์ Docker แล้ว”

รันงานเป็นระยะ : run.sh

สร้าง entrypoint.sh

#!/bin/bash

# Start the run once job.
echo "Docker container has been started"

# Setup a cron schedule
echo "* * * * * /run.sh >> /var/log/cron.log 2>&1
# This extra line makes it a valid cron" > scheduler.txt

crontab scheduler.txt
cron -f

มาทำความเข้าใจกับ crontab ที่ติดตั้งในไฟล์กันดีกว่า

* * * * *: กำหนดการ Cron; งานต้องทำงานทุกนาที คุณสามารถอัปเดตกำหนดการตามความต้องการของคุณ

/run.sh: พา ธ ไปยังไฟล์สคริปต์ที่ต้องรันเป็นระยะ

/var/log/cron.log: ชื่อไฟล์เพื่อบันทึกผลลัพธ์ของงาน cron ที่กำหนดไว้

2>&1: บันทึกข้อผิดพลาด (ถ้ามี) จะถูกเปลี่ยนเส้นทางไปยังไฟล์เอาต์พุตเดียวกันกับที่ใช้ด้านบน

หมายเหตุ : อย่าลืมเพิ่มบรรทัดใหม่พิเศษเนื่องจากทำให้เป็น cron ที่ถูกต้อง Scheduler.txt: การตั้งค่า cron ที่สมบูรณ์จะถูกเปลี่ยนเส้นทางไปยังไฟล์

การใช้ตัวแปรสภาพแวดล้อมเฉพาะของระบบ / ผู้ใช้ใน cron

งาน cron ที่แท้จริงของฉันคาดว่าจะมีข้อโต้แย้งส่วนใหญ่เนื่องจากตัวแปรสภาพแวดล้อมที่ส่งผ่านไปยังคำสั่งเรียกใช้นักเทียบท่า แต่ด้วย bash ฉันไม่สามารถใช้ตัวแปรสภาพแวดล้อมใด ๆ ที่เป็นของระบบหรือคอนเทนเนอร์นักเทียบท่าได้

จากนั้นสิ่งนี้เกิดขึ้นเป็นคำตอบสำหรับปัญหานี้:

  1. เพิ่มบรรทัดต่อไปนี้ใน entrypoint.sh
declare -p | grep -Ev 'BASHOPTS|BASH_VERSINFO|EUID|PPID|SHELLOPTS|UID' > /container.env
  1. อัปเดตการตั้งค่า cron และระบุ -
SHELL=/bin/bash
BASH_ENV=/container.env

ในที่สุดคุณentrypoint.shควรดูเหมือน

#!/bin/bash

# Start the run once job.
echo "Docker container has been started"

declare -p | grep -Ev 'BASHOPTS|BASH_VERSINFO|EUID|PPID|SHELLOPTS|UID' > /container.env

# Setup a cron schedule
echo "SHELL=/bin/bash
BASH_ENV=/container.env
* * * * * /run.sh >> /var/log/cron.log 2>&1
# This extra line makes it a valid cron" > scheduler.txt

crontab scheduler.txt
cron -f

สุดท้าย แต่ไม่ท้ายสุด: สร้างไฟล์ Dockerfile

FROM ubuntu:16.04
MAINTAINER Himanshu Gupta

# Install cron
RUN apt-get update && apt-get install -y cron

# Add files
ADD run.sh /run.sh
ADD entrypoint.sh /entrypoint.sh

RUN chmod +x /run.sh /entrypoint.sh

ENTRYPOINT /entrypoint.sh

แค่นั้นแหละ. สร้างและเรียกใช้ภาพนักเทียบท่า!


1
@himanshuIIITian ฉันลองสิ่งนี้ปัญหาคือว่าสคริปต์ของ "run one job" ไม่เคยกลับมาและข้าวโพด -f ไม่กลับมา ... สิ่งนี้ไม่ได้ผลสำหรับฉันความคิดใด ๆ ขอบคุณ
Doron Levi

@DoronLevi - คุณกรุณาแบ่งปันบันทึกเพื่อดูปัญหาได้หรือไม่ หรือคุณสามารถตรวจสอบรหัสทั้งหมดได้จากที่นี่ - github.com/nehabhardwaj01/docker-cron
himanshuIIITian

ขอบคุณสำหรับความคิดเห็น. ฉันดีใจที่คำตอบนั้นมีประโยชน์
himanshuIIITian

1

งาน Cron ถูกเก็บไว้ใน / var / spool / cron / crontabs (ตำแหน่งทั่วไปใน distros ทั้งหมดที่ฉันรู้จัก) BTW คุณสามารถสร้างแท็บ cron ใน bash โดยใช้สิ่งต่อไปนี้:

crontab -l > cronexample
echo "00 09 * * 1-5 echo hello" >> cronexample
crontab cronexample
rm cronexample

สิ่งนี้จะสร้างไฟล์ชั่วคราวด้วยงาน cron จากนั้นตั้งโปรแกรมโดยใช้ crontab บรรทัดสุดท้ายลบไฟล์ชั่วคราว


cronภูตไม่ทำงานได้ตามปกติในภาชนะ
Matt

@BhargavNanekalva จะต้องมีการตั้งค่าเฉพาะในภาชนะที่คำตอบนี้ไม่ได้อยู่
Matt

@ แมทคุณช่วยชี้ให้เห็นว่ามันควรจะระบุในภาชนะ? . ฉันทำ crontab -l และคำสั่งจะปรากฏขึ้น - kagda.ru/i/6d014816d43_29-06-2017-11:38:59_6d01.png แต่ก็ยังไม่ทำงาน
Tebe

@ Копать_Шо_я_нашелคุณต้องเรียกใช้crondนอกเหนือจากบริการที่คุณกำลังใช้งานในคอนเทนเนอร์ตามปกติโดยมีผู้จัดการบริการเช่น s6 อาจถามว่าเป็นคำถามที่จะได้คำตอบที่ถูกต้อง
Matt

1

เมื่อทำงานกับภาพที่ถูกตัดทอนบางส่วนที่ จำกัด การเข้าถึงรูทฉันต้องเพิ่มผู้ใช้ของฉันไปยัง sudoers และทำงานเป็น sudo cron

FROM node:8.6.0
RUN apt-get update && apt-get install -y cron sudo

COPY crontab /etc/cron.d/my-cron
RUN chmod 0644 /etc/cron.d/my-cron
RUN touch /var/log/cron.log

# Allow node user to start cron daemon with sudo
RUN echo 'node ALL=NOPASSWD: /usr/sbin/cron' >>/etc/sudoers

ENTRYPOINT sudo cron && tail -f /var/log/cron.log

บางทีนั่นอาจช่วยใครซักคน


ฉันเชื่อว่าภาพโหนดใช้ผู้ใช้โหนด; ดังนั้นคุณอาจจำเป็นต้องเพิ่มการอนุญาตสำหรับผู้ใช้รายนั้น
bozdoz

1

ดังนั้นปัญหาของฉันก็เหมือนกัน docker-compose.ymlการแก้ไขคือการเปลี่ยนส่วนคำสั่งใน

จาก

คำสั่ง: crontab / etc / crontab && tail -f / etc / crontab

ถึง

คำสั่ง: crontab / etc / crontab

คำสั่ง: tail -f / etc / crontab

ปัญหาเป็น '&&' ระหว่างคำสั่ง หลังจากลบสิ่งนี้มันก็ไม่เป็นไร


-1

วิธีที่แข็งแกร่งที่สุดที่ฉันค้นพบในตอนนี้คือเรียกใช้ cron container อิสระ - ติดตั้งไคลเอ็นต์ docker และผูกเมาถุงเท้า docker เพื่อให้คุณสามารถพูดคุยกับเซิร์ฟเวอร์ docker บนโฮสต์

จากนั้นใช้ env vars สำหรับงาน cron แต่ละงานและสคริปต์จุดเข้าใช้งานเพื่อสร้าง / etc / crontab

นี่คือภาพที่ฉันสร้างขึ้นโดยใช้หลักการนี้และใช้มันในการผลิตในช่วง 3-4 ปีที่ผ่านมา

https://www.vip-consult.solutions/post/better-docker-cron#content


คำตอบควรอยู่ในตัวเองและไม่เชื่อมโยงกับแหล่งข้อมูลภายนอก
Nicolas Bouliane

-2

ลองใช้อัญมณีนาฬิกาเพื่อกำหนดเวลางาน ทำตามขั้นตอนที่ให้ไว้ในลิงค์นี้

http://fuzzyblog.io/blog/rails/2017/05/11/adding-cron-to-a-dockerized-rails-application-using-clockwork.html

คุณสามารถเรียกใช้งาน rake ในไฟล์ lib / clock.rb ดังนี้

every(1.day, 'Import large data from csv files', :at => '5:00') do |job|
  `rake 'portal:import_data_from_csv'`
end

สร้างคอนเทนเนอร์แยกต่างหากในไฟล์เขียนนักเทียบท่า & เรียกใช้คำสั่งด้านล่างภายในคอนเทนเนอร์

command: bundle exec clockwork lib/clock.rb

1
เป็นความคิดที่ดีที่จะใช้เครื่องมืออื่นสำหรับกำหนดการ อย่างไรก็ตามคำถามนี้ถาม cron โดยเฉพาะดังนั้นข้อเสนอแนะของคุณน่าจะดีกว่าในฐานะที่เป็นความคิดเห็นของคำถามในความคิดเห็นของฉัน
Richard Kiefer
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.