쉘 스크립트를 호출하는 도커 컨테이너 내에서 cronjob을 실행하려고합니다.
어제 웹과 스택 오버플로를 검색했지만 실제로 작동하는 솔루션을 찾을 수 없었습니다.
어떻게해야합니까?
편집하다:
주어진 간격마다 쉘 스크립트를 호출하는 작동하는 docker cron 컨테이너로 주석 처리 된 github 저장소 를 만들었습니다 .
쉘 스크립트를 호출하는 도커 컨테이너 내에서 cronjob을 실행하려고합니다.
어제 웹과 스택 오버플로를 검색했지만 실제로 작동하는 솔루션을 찾을 수 없었습니다.
어떻게해야합니까?
편집하다:
주어진 간격마다 쉘 스크립트를 호출하는 작동하는 docker cron 컨테이너로 주석 처리 된 github 저장소 를 만들었습니다 .
답변:
해당 이미지에서 시작된 컨테이너가 작업을 실행하기 위해 crontab을 이미지로 복사 할 수 있습니다.
자세한 내용은 " 부두 노동자와 cron 작업을 실행 에서" 줄리앙 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 가 지적한 바와 같이 :
문제에 대한 빠른 참고 사항 :
스크립트 파일을 추가하고 cron에이를 실행하도록 지시하는 경우, 잊어 버린 경우 Cron이 자동으로 실패 한다는 것을 기억하십시오 .
RUN chmod 0744 /the_script
또는 hugoShaka 의 답변에 설명 된대로 작업 자체가 로그 파일 대신 stdout / stderr로 직접 리디렉션되도록하십시오 .
* * * * * root echo hello > /proc/1/fd/1 2>/proc/1/fd/2
마지막 Dockerfile 줄을
CMD ["cron", "-f"]
(에 대한 참조 cron -f
크론 "전경"라고하는 것입니다있는) " 우분투는 고정 표시기 cron -f
작동하지 않습니다 "
빌드하고 실행하십시오.
sudo docker build --rm -t ekito/cron-example .
sudo docker run -t -i ekito/cron-example
인내심을 갖고 2 분 동안 기다리면 명령 행이 표시되어야합니다.
Hello world
Hello world
참고 수행
tail
이 이미지 빌드하는 동안 생성 된 경우 올바른 파일을 표시하지 않을 수 있습니다.
이 경우 테일이 올바른 파일을 선택하도록 컨테이너 런타임 동안 파일을 작성하거나 터치해야합니다.
" 도커 끝에 출력이 표시되지 않음tail -f
CMD
"을 참조하십시오.
-y
않도록 고정 표시기 빌드 종료에 크론을 설치하기
crontab -l
이 없습니다 라는 메시지가 표시되고 화면에 아무 것도 표시되지 않습니다. 그러나 '/etc/cron.d/'를 확인하면 crontab 파일이 있고 (더 놀랍게도) 확인 /var/log/cron.log
하면 스크립트가 실행되고 있음을 알 수 있습니다 (파일 내용에 추가됨 Hello World
). Dockerfile에서이 이미지를 가져옵니다 FROM phusion/baseimage:0.10.0
. 행동 불일치에 대한 아이디어가 있습니까?
채택 된 솔루션 은 프로덕션 환경에서 위험 할 수 있습니다 .
도커에서는 컨테이너 당 하나의 프로세스 만 실행해야합니다.
당신이 사용하는 경우 CMD cron && tail -f /var/log/cron.log
실행하기 위해 기본적으로 포크 크론 프로세스를 cron
백그라운드에서 주요 프로세스 종료하고 실행하자 tailf
전경. 백그라운드 크론 프로세스가 중지되거나 실패 할 수 있습니다. 컨테이너는 여전히 자동으로 실행되며 오케스트레이션 도구는 다시 시작하지 않습니다.
당신은 당신의 고정 표시기에 직접 크론의 명령 출력을 리디렉션하여 이러한 일을 방지 할 수 있습니다
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"]
cron -f
"크론 전경"입니다. 더 많은 가시성을 위해 위의 내 답변을 포함 시켰습니다. +1
간단하고 가벼운 이미지를 사용하려는 사람들을 위해 :
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 는 다음 형식의 cronjob을 포함하는 파일입니다.
* * * * * echo "hello stackoverflow" >> /test_file 2>&1
# remember to end this file with an empty new line
> /proc/1/fd/1 2> /proc/1/fd/2
리디렉션을 사용하여 docker logs에서 직접 cronjobs 출력에 액세스하십시오.
-d 8
매개 변수를 지원하는 크론은 표준 크론이 아니며 busybox의 크론 드 명령입니다. 예를 들어 우분투에서 이것을 다음과 같이 실행할 수 있습니다 busybox crond -f -d 8
. 이전 버전의 경우을 사용해야 -L /dev/stdout/
합니다.
docker run -v ${PWD}/cronjobs:/etc/crontabs/root alpine:3.6 crond -f -d 8
. @Groostav 당신은 Docker Compose에서 비슷한 것을 사용할 수 있습니다.
CMD ["crond"
또는 CMD ["cron"
?
@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"
CMD 대신 ENTRYPOINT를 선호하는 경우 위의 CMD를
ENTRYPOINT cron start && tail -f /var/log/cron.log
RUN apt-get update && apt-get -y install cron
그렇지 않으면 패키지를 찾을 수 없습니다cron
RUN cat $APP_HOME/crons/* | crontab
매력 :)처럼
cron
진입 점 스크립트에 추가 하는 것이 가장 좋은 옵션 인 것 같습니다. ENTRYPOINT [ "entrypoint.sh"]
cron (스케줄러)을 지원하는 작업 러너 인 Tasker 를 사용하는 것이 다른 방법 입니다.
왜 ? 때로는 cron 작업을 실행하려면 기본 이미지 (python, java, nodejs, ruby)를 크론과 혼합해야합니다. 그것은 유지해야 할 또 다른 이미지를 의미합니다. Tasker는 크론과 컨테이너를 분리하여이를 피합니다. 명령을 실행하려는 이미지에 초점을 맞추고이를 사용하도록 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 개의 작업이 있으며, 모든 작업은 1 분마다 실행되며 ( every: minute
) 섹션에 script
정의 된 이미지 내에서 각각의 코드 를 실행합니다 image
.
그냥 실행 docker-compose up
하고 작동하는지 확인하십시오. 다음은 전체 설명서가 포함 된 Tasker 저장소입니다.
docker exec
지정된 컨테이너 에서 사용 하는 것 입니다.
Docker exec
인터페이스 를 통해 컨테이너에서 실행중인 프로세스 옆에 작업을 실행하는 것이 목표이지만 관심이있을 수 있습니다.
컨테이너를 관찰하고 메타 데이터에 정의 된 작업을 예약하는 데몬을 작성했습니다. 예:
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
'클래식', 크론과 같은 구성도 가능합니다.
docker exec <container_name> <some_command>
하며 일정 별 명령처럼 작동합니다 .
다른 답변을 기반으로 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
참고로 이미지 는 여기에 있습니다 .
다른 호스트에 컨테이너를 배포 할 때 프로세스가 자동으로 시작되지 않습니다. 컨테이너 내에서 'cron'서비스가 실행 중인지 확인해야합니다. 우리의 경우 Cron 서비스를 시작하기 위해 다른 서비스와 함께 Supervisord를 사용하고 있습니다.
[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
docker exec를 통해 서비스에 명령을 실행하는 전용 컨테이너에 cronjob을 정의하십시오.
응집력이 높으며 실행중인 스크립트는 서비스에 대해 정의한 환경 변수에 액세스 할 수 있습니다.
#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
오류를.
windows 용 docker를 사용하는 경우 crontab 파일을 Windows에서 우분투 컨테이너로 가져 오려면 줄 끝 형식을 CRLF에서 LF로 변경해야합니다 (즉, dos에서 unix로)해야합니다. 그렇지 않으면 cron-job이 작동하지 않습니다. 다음은 실제 예입니다.
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
docker 컨테이너에서 cron 작업을 디버깅하는 것은 지루한 작업이므로 실제로 알아내는 데 몇 시간이 걸렸습니다. 코드가 작동하지 않는 다른 사람을 도울 수 있기를 바랍니다.
위의 예 에서이 조합을 만들었습니다.
나노에서 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
정기적으로 실행되어야하는 작업으로 run.sh와 같은 스크립트 파일을 작성하십시오.
#!/bin/bash
timestamp=`date +%Y/%m/%d-%H:%M:%S`
echo "System path is $PATH at $timestamp"
저장하고 종료.
도커 컨테이너화 중에 여러 작업을 시작하려면 시작점 파일을 사용하여 모두 실행하십시오.
진입 점 파일은 docker run 명령이 실행될 때 작동하는 스크립트 파일입니다. 따라서 실행하려는 모든 단계를이 스크립트 파일에 넣을 수 있습니다.
예를 들어, 두 가지 작업을 실행해야합니다.
한 번 작업 실행 : echo "Docker 컨테이너가 시작되었습니다"
정기적 인 작업 실행 : run.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 스케줄; 작업은 1 분마다 실행해야합니다. 요구 사항에 따라 일정을 업데이트 할 수 있습니다.
/run.sh
: 정기적으로 실행되는 스크립트 파일의 경로
/var/log/cron.log
: 스케줄 된 cron 작업의 출력을 저장하기위한 파일 이름입니다.
2>&1
: 오류 로그 (있는 경우)도 위에서 사용한 것과 동일한 출력 파일로 리디렉션됩니다.
참고 : 유효한 cron으로 만들기 때문에 새 줄을 추가하는 것을 잊지 마십시오.
Scheduler.txt
: 전체 cron 설정이 파일로 리디렉션됩니다.
내 실제 크론 작업은 환경 변수가 docker run 명령에 전달 될 때 대부분의 인수를 기대했습니다. 그러나 bash를 사용하면 시스템 또는 도커 컨테이너에 속한 환경 변수를 사용할 수 없었습니다.
그런 다음이 문제에 대한 해결책으로 나타났습니다.
declare -p | grep -Ev 'BASHOPTS|BASH_VERSINFO|EUID|PPID|SHELLOPTS|UID' > /container.env
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
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
그게 다야. Docker 이미지를 빌드하고 실행하십시오!
Cron 작업은 / var / spool / cron / crontabs (알고있는 모든 배포판의 공통 위치)에 저장됩니다. BTW, bash에서 다음과 같은 것을 사용하여 cron 탭을 만들 수 있습니다.
crontab -l > cronexample
echo "00 09 * * 1-5 echo hello" >> cronexample
crontab cronexample
rm cronexample
cron 작업으로 임시 파일을 만든 다음 crontab을 사용하여 프로그래밍합니다. 마지막 줄은 임시 파일을 제거합니다.
cron
데몬은 일반적으로 컨테이너에서 실행되지 않습니다.
crond
컨테이너에서 실행중인 서비스 외에 일반적으로 s6와 같은 서비스 관리자를 사용하여 실행해야합니다. 아마 정답을 얻기위한 질문으로 물어보십시오
루트 액세스를 제한하는 일부 축소 된 이미지에서 실행할 때 사용자를 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
어쩌면 누군가를 도울 수 있습니다.
내가 지금까지 찾은 가장 강력한 방법은 독립적 인 cron 컨테이너를 실행하는 것입니다-docker 클라이언트를 설치하고 docker sock를 바인드 마운트하여 호스트의 docker 서버와 통신 할 수 있습니다.
그런 다음 각 cron 작업 및 시작점 스크립트에 대해 env vars를 사용하여 / etc / crontab을 생성하십시오.
이 원리를 사용하여 지난 3-4 년 동안 프로덕션에서 사용하여 만든 이미지는 다음과 같습니다.
https://www.vip-consult.solutions/post/better-docker-cron#content
시계 보석을 사용하여 작업을 예약하십시오. 이 링크에 제공된 단계를 따르십시오.
아래와 같이 lib / clock.rb 파일에서 레이크 작업을 호출 할 수 있습니다.
every(1.day, 'Import large data from csv files', :at => '5:00') do |job|
`rake 'portal:import_data_from_csv'`
end
docker-compose 파일에 별도의 컨테이너를 만들고 컨테이너 내부에서 아래 명령을 실행하십시오.
command: bundle exec clockwork lib/clock.rb
RUN apt-get update && apt-get install cron