{"id":157117,"date":"2021-01-18T16:00:42","date_gmt":"2021-01-18T13:00:42","guid":{"rendered":"https:\/\/en.buradabiliyorum.com\/how-to-use-cron-with-your-docker-containers-cloudsavvy-it\/"},"modified":"2021-01-18T16:00:42","modified_gmt":"2021-01-18T13:00:42","slug":"how-to-use-cron-with-your-docker-containers-cloudsavvy-it","status":"publish","type":"post","link":"https:\/\/buradabiliyorum.com\/en\/how-to-use-cron-with-your-docker-containers-cloudsavvy-it\/","title":{"rendered":"#How to Use Cron With Your Docker Containers \u2013 CloudSavvy IT"},"content":{"rendered":"<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_85 counter-hierarchy ez-toc-counter ez-toc-custom ez-toc-container-direction\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Table of Contents<\/p>\n<label for=\"ez-toc-cssicon-toggle-item-6a30b10120c06\" class=\"ez-toc-cssicon-toggle-label\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #dd3333;color:#dd3333\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #dd3333;color:#dd3333\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/label><input type=\"checkbox\"  id=\"ez-toc-cssicon-toggle-item-6a30b10120c06\" checked aria-label=\"Toggle\" \/><nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-use-cron-with-your-docker-containers-cloudsavvy-it\/#Using_the_Hosts_Crontab\" >Using the Host\u2019s Crontab<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-use-cron-with-your-docker-containers-cloudsavvy-it\/#Using_Cron_Within_Your_Containers\" >Using Cron Within Your Containers<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-use-cron-with-your-docker-containers-cloudsavvy-it\/#Separating_Cron_From_Your_Applications_Services\" >Separating Cron From Your Application\u2019s Services<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-use-cron-with-your-docker-containers-cloudsavvy-it\/#Using_Kubernetes_Cron_Jobs\" >Using Kubernetes Cron Jobs<\/a><\/li><\/ul><\/nav><\/div>\n<p><strong>&#8220;#How to Use Cron With Your Docker Containers \u2013 CloudSavvy IT&#8221;<\/strong><\/p>\n<div id=\"article-content-area\">\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-9034\" src=\"https:\/\/www.cloudsavvyit.com\/thumbcache\/0\/0\/78cc37c3a66e5df9b2a9dc8cd64461c7\/p\/uploads\/2021\/01\/6dc7b5a0.jpeg\" alt=\"Docker\" width=\"1602\" height=\"902\" onload=\"pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);\" onerror=\"this.onerror=null;pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);\"\/><\/p>\n<p>Running background tasks on a schedule is a standard requirement of backend services. Getting setup used to be simple \u2013 you\u2019d define your tasks in your server\u2019s <code>crontab<\/code> and call it a day. Let\u2019s look at how you can utilise <code>cron<\/code> while using Docker for deployment.<\/p>\n<p>Containerising your services increases developer productivity. Simultaneously, it can leave you wondering how traditional sysadmin concerns map to Docker concepts. You\u2019ve got several options when using <code>cron<\/code> with Docker containers and we\u2019ll explore them below in order of suitability. Before continuing, make sure you\u2019ve built a Docker image of your <a href=\"https:\/\/buradabiliyorum.com\/en\/category\/download-scripts-themes-apps\/\" data-internallinksmanager029f6b8e52c=\"9\" title=\"Download Scripts &amp; Themes &amp; Apps\" target=\"_blank\" rel=\"noopener\">app<\/a>lication.<\/p>\n<h2 id=\"using-the-hosts-crontab\"><span class=\"ez-toc-section\" id=\"Using_the_Hosts_Crontab\"><\/span>Using the Host\u2019s Crontab<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>At its most basic, you can always utilise the <code>cron<\/code> installation of the host that\u2019s running your Docker Engine. Make sure <code>cron<\/code> is installed and then edit the system\u2019s <code>crontab<\/code> as normal.<\/p>\n<p>You can use <code>docker exec<\/code> to run a command within an existing container:<\/p>\n<pre>*\/5 * * * * docker exec example_app_container \/example-scheduled-task.sh<\/pre>\n<p>This will only work if you can be sure of the container\u2019s name ahead of time. It\u2019s normally better to create a new container which exists solely to run the task:<\/p>\n<pre>*\/5 * * * * docker run --rm example_app_image:latest \/example-scheduled-task.sh<\/pre>\n<p>Every five minutes, your system\u2019s <code>cron<\/code> installation will create a new Docker container using your app\u2019s image. Docker will execute the <code>\/example-scheduled-task.sh<\/code> script within the container. The container will be destroyed (<code>--rm<\/code>) once the script exits.<\/p>\n<h2 id=\"using-cron-within-your-containers\"><span class=\"ez-toc-section\" id=\"Using_Cron_Within_Your_Containers\"><\/span>Using Cron Within Your Containers<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Using the host\u2019s <code>crontab<\/code> breaks Docker\u2019s containerisation as the scheduled tasks require manual setup on your system. You\u2019ll need to ensure <code>cron<\/code> is installed on each host you deploy to. While it can be useful in development, you should look to integrate <code>cron<\/code> into your Dockerised services when possible.<\/p>\n<p>Most popular Docker base images do not include the <code>cron<\/code> daemon by default. You can install it within your <code>Dockerfile<\/code> and then register your application\u2019s <code>crontab<\/code>.<\/p>\n<p>First, create a new <code>crontab<\/code> file within your codebase:<\/p>\n<pre>*\/5 * * * * \/usr\/bin\/sh \/example-scheduled-task.sh<\/pre>\n<p>Next, amend your <code>Dockerfile<\/code> to install <code>cron<\/code> and register your <code>crontab<\/code> \u2013 here\u2019s how you can do that with a Debian-based image:<\/p>\n<pre>RUN apt-get update &amp;&amp; apt-get install -y cron&#13;\nCOPY example-crontab \/etc\/cron.d\/example-crontab&#13;\nRUN chmod 0644 \/etc\/cron.d\/example-crontab &amp;&amp;&#13;\n    crontab \/etc\/cron.d\/example-crontab<\/pre>\n<p>We install <code>cron<\/code> and copy our codebase\u2019s <code>crontab<\/code> into the <code>\/etc\/cron.d<\/code> directory. Next, we need to amend the permissions on our <code>crontab<\/code> to make sure it\u2019s accessible to <code>cron<\/code>. Finally, use the <code>crontab<\/code> command to make the file known to the <code>cron<\/code> daemon.<\/p>\n<p>To complete this setup, you\u2019ll need to amend your image\u2019s command or entrypoint to start the <code>cron<\/code> daemon when containers begin to run. You can\u2019t achieve this with a <code>RUN<\/code> stage in your <code>Dockerfile<\/code> because these are transient steps which don\u2019t persist beyond the image\u2019s build phase. The service would be started within the ephemeral container used to build the layer, not the final containers running the completed image.<\/p>\n<p>If your container\u2019s only task is to run <code>cron<\/code> \u2013 which we\u2019ll discuss more below \u2013 you can add <code>ENTRYPOINT [\"cron\", \"-f\"]<\/code> to your <code>Dockerfile<\/code> to launch it as the foreground process. If you need to keep another process in the foreground, such as a web server, you should create a dedicated entrypoint script (e.g.\u00a0<code>ENTRYPOINT [\"bash\", \"init.sh\"]<\/code>) and add <code>service cron start<\/code> as a command within that file.<\/p>\n<h2 id=\"separating-cron-from-your-applications-services\"><span class=\"ez-toc-section\" id=\"Separating_Cron_From_Your_Applications_Services\"><\/span>Separating Cron From Your Application\u2019s Services<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Implementing the setup described in the preceding section provides a more robust solution than relying on the host\u2019s <code>crontab<\/code>. Adding the <code>cron<\/code> daemon to the containers that serve your application ensures anyone consuming your Docker image will have scheduled tasks setup automatically.<\/p>\n<p>This still results in mixing of concerns though. Your containers end up with two responsibilities \u2013 firstly, to provide the application\u2019s functionality, and secondly, to keep <code>cron<\/code> alive and run the scheduled tasks. Ideally, each container should provide one specific unit of functionality.<\/p>\n<p>Wherever possible, you should run your <code>cron<\/code> tasks in a separate container to your application. If you\u2019re creating a web backend, that would mean one container to provide your web server and another which runs <code>cron<\/code> in the foreground.<\/p>\n<p>Without this separation, you\u2019ll be unable to use an orchestrator like Docker Swarm or Kubernetes to run multiple replicas of your application. Each container would run its own <code>cron<\/code> daemon, causing scheduled tasks to run multiple times. This can be mitigated by using lock files bound into a shared Docker volume. Nonetheless, it\u2019s more maintainable to address the root problem and introduce a dedicated container for the <code>cron<\/code> daemon.<\/p>\n<p><a href=\"https:\/\/buradabiliyorum.com\/en\/category\/general\/\" data-internallinksmanager029f6b8e52c=\"3\" title=\"General\" target=\"_blank\" rel=\"noopener\">General<\/a>ly, you\u2019ll want both containers to be based on your application\u2019s Docker image. They\u2019ll each need connections to your service\u2019s Docker volumes and networks. This will ensure the <code>cron<\/code> container has an identical environment to the application container, with the only difference being the foreground process.<\/p>\n<p>This is not a hard-and-fast rule \u2013 in some projects, your scheduled tasks might be trivial scripts which operate independently of your codebase. In that case, the <code>cron<\/code> container may use a minimal base image and do away with connections to unnecessary peripheral resources.<\/p>\n<p>One way to get setup with a separate <code>cron<\/code> container would be to use <code>docker-compose<\/code>. You\u2019d define the <code>cron<\/code> container as an extra service. You could use your application\u2019s base image, overriding the entrypoint command to start the <code>cron<\/code> daemon. Using <code>docker-compose<\/code> also simplifies attaching the container to any shared volumes and networks it requires.<\/p>\n<div class=\"wp-geshi-highlight-wrap5\">\n<div class=\"wp-geshi-highlight-wrap4\">\n<div class=\"wp-geshi-highlight-wrap3\">\n<div class=\"wp-geshi-highlight-wrap2\">\n<div class=\"wp-geshi-highlight-wrap\">\n<div class=\"wp-geshi-highlight\">\n<div class=\"yml\">\n<pre class=\"de1\">version: \"3\"&#13;\n\u00a0\nservices:&#13;\n  app:&#13;\n    image: demo-image:latest&#13;\n    volumes:&#13;\n      - data:\/app-data&#13;\n  cron:&#13;\n    image: demo-image:latest&#13;\n    entrypoint: \/bin\/bash&#13;\n    command: [\"cron\", \"-f\"]&#13;\n    volumes:&#13;\n      - data:\/app-data&#13;\n\u00a0\nvolumes:&#13;\n  data:<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p>Using the above example, one container serves our application using the default entrypoint in the image. Make sure this does <em>not<\/em> start the <code>cron<\/code> daemon! The second container overrides the image\u2019s entrypoint to run <code>cron<\/code>. As long as the image still has <code>cron<\/code> installed and your <code>crontab<\/code> configured, you can use <code>docker-compose up<\/code> to bring up your application.<\/p>\n<h2 id=\"using-kubernetes-cron-jobs\"><span class=\"ez-toc-section\" id=\"Using_Kubernetes_Cron_Jobs\"><\/span>Using Kubernetes Cron Jobs<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Finally, let\u2019s look at a simple example of running scheduled tasks within Kubernetes. Kubernetes comes with its own <code>CronJob<\/code> resource which you can use in your manifests.<\/p>\n<p>You don\u2019t need to install <code>cron<\/code> in your image or setup specialised containers if you\u2019re using Kubernetes. Be aware that <code>CronJob<\/code> is a beta resource which may change in future Kubernetes releases.<\/p>\n<div class=\"wp-geshi-highlight-wrap5\">\n<div class=\"wp-geshi-highlight-wrap4\">\n<div class=\"wp-geshi-highlight-wrap3\">\n<div class=\"wp-geshi-highlight-wrap2\">\n<div class=\"wp-geshi-highlight-wrap\">\n<div class=\"wp-geshi-highlight\">\n<div class=\"yml\">\n<pre class=\"de1\">apiVersion: batch\/v1beta1&#13;\nkind: CronJob&#13;\nmetadata:&#13;\n  name: my-cron&#13;\n  namespace: my-namespace&#13;\nspec:&#13;\n  schedule: \"*\/5 * * * *\"&#13;\n  concurrencyPolicy: Forbid&#13;\n  jobTemplate:&#13;\n    spec:&#13;\n      template:&#13;\n        spec:&#13;\n          containers:&#13;\n            - name: my-container&#13;\n              image: my-image:latest&#13;\n              command: [\"\/bin\/bash\", \"\/my-cron-script.sh\"]&#13;\n          restartPolicy: OnFailure<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p>Apply the above manifest to your cluster to create a new <code>cron<\/code> job which will run <code>\/my-cron-script.sh<\/code> within your container every five minutes. The frequency is given as a regular <code>cron<\/code> definition to the <code>schedule<\/code> key in the resource\u2019s <code>spec<\/code>.<\/p>\n<p>You can customise the <code>ConcurrencyPolicy<\/code> to <a rel=\"nofollow noopener\" target=\"_blank\" href=\"https:\/\/kubernetes.io\/docs\/tasks\/job\/automated-tasks-with-cron-jobs\/\">control whether Kubernetes<\/a> allows your jobs to overlap. It defaults to <code>Allow<\/code> but can be changed to <code>Forbid<\/code> (prevent new jobs from starting while one already exists) or <code>Replace<\/code> (terminate an existing job as soon as a new one starts).<\/p>\n<p>Using Kubernetes\u2019s built-in resource is the recommended way to manage scheduled tasks within your clusters. You can easily access job logs and don\u2019t need to worry about preparing your containers for use with <code>cron<\/code>. You just need to produce a Docker image which contains everything your tasks need to run. Kubernetes will handle creating and destroying container instances on the schedule you specify.\n<\/div>\n<blockquote><p><strong><span style=\"color: #ff6600;\">If you liked the article, do not forget to share it with your friends. Follow us on\u00a0<span style=\"color: #ff0000;\"><a style=\"color: #ff0000;\" href=\"https:\/\/news.google.com\/publications\/CAAqBwgKMLG0nwswvr63Aw\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Google News<\/a><\/span>\u00a0too, click on the star and choose us from your favorites.<\/span><\/strong><\/p><\/blockquote>\n<blockquote>\n<p style=\"text-align: center;\">For forums sites go to <span style=\"color: #ff9900;\"><a style=\"color: #ff9900;\" href=\"https:\/\/forum.buradabiliyorum.com\/\" target=\"_blank\" rel=\"noopener\">Forum.BuradaBiliyorum.Com<\/a><\/span><\/strong><\/p>\n<\/blockquote>\n<blockquote>\n<p style=\"text-align: center;\"><strong>If you want to read more like this article, you can visit our <span style=\"color: #ff9900;\"><a style=\"color: #ff9900;\" href=\"https:\/\/en.buradabiliyorum.com\/technology\/\" target=\"_blank\" rel=\"noopener\">Technology category.<\/a><\/span><\/strong><\/p>\n<\/blockquote>\n<p><span style=\"color: black;\"><a style=\"color: #ff9900;\" href=\"https:\/\/www.cloudsavvyit.com\/9033\/how-to-use-cron-with-your-docker-containers\/\" target=\"_blank\" rel=\"noopener\">Source<\/a><\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>&#8220;#How to Use Cron With Your Docker Containers \u2013 CloudSavvy IT&#8221; Running background tasks on a schedule is a standard requirement of backend services. Getting setup used to be simple \u2013 you\u2019d define your tasks in your server\u2019s crontab and call it a day. Let\u2019s look at how you can utilise cron while using Docker&#8230;<\/p>\n","protected":false},"author":1,"featured_media":157118,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"fifu_image_url":"https:\/\/www.cloudsavvyit.com\/p\/uploads\/2021\/01\/6dc7b5a0.jpeg","fifu_image_alt":"","footnotes":""},"categories":[18],"tags":[],"class_list":["post-157117","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-technology"],"_links":{"self":[{"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/posts\/157117","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/comments?post=157117"}],"version-history":[{"count":0,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/posts\/157117\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/media\/157118"}],"wp:attachment":[{"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/media?parent=157117"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/categories?post=157117"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/tags?post=157117"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}