<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Moti Lavian</title>
    <description>The latest articles on DEV Community by Moti Lavian (@motilavian).</description>
    <link>https://dev.to/motilavian</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F596002%2Ff410b532-bd67-498b-ad00-1c4b73fa20f2.jpeg</url>
      <title>DEV Community: Moti Lavian</title>
      <link>https://dev.to/motilavian</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/motilavian"/>
    <language>en</language>
    <item>
      <title>Running scheduled jobs / tasks using GitLab CI/CD</title>
      <dc:creator>Moti Lavian</dc:creator>
      <pubDate>Sun, 14 Mar 2021 11:40:29 +0000</pubDate>
      <link>https://dev.to/motilavian/running-scheduled-jobs-tasks-using-gitlab-ci-cd-5e73</link>
      <guid>https://dev.to/motilavian/running-scheduled-jobs-tasks-using-gitlab-ci-cd-5e73</guid>
      <description>&lt;h1&gt;
  
  
  TL;DR
&lt;/h1&gt;

&lt;p&gt;I use GitLab's CI/CD free feature to automatically run code in the cloud.&lt;/p&gt;




&lt;h1&gt;
  
  
  Background
&lt;/h1&gt;

&lt;p&gt;Every now and then I come across the need to automate a task (written in code) to be performed periodically, so that it'll run by itself, without my intervention.&lt;br&gt;
Such tasks can be submitting an online form, scraping data from a website, running some script that updates something else online, etc.&lt;br&gt;
I obviously don't want this code to run on my computer, as it is not on and ready all the time, nor do I want to setup and plug in a Raspberry Pi device or alike just for that.&lt;/p&gt;

&lt;p&gt;Now, running it periodically sounded like a very simple and straight-forward task, but it turned out to be a bit tricky! After some research (&lt;a href="https://lmgtfy.app/?q=free+cron+scheduler" rel="noopener noreferrer"&gt;not too much&lt;/a&gt;, I admit), I was not able to find a free and easy-to-use tool / service that would allow me to have some piece of code run periodically in the cloud. I did not want to pull out the bigger guns such as &lt;a href="https://aws.amazon.com/lambda/" rel="noopener noreferrer"&gt;AWS&lt;/a&gt; or &lt;a href="https://cloud.google.com/functions" rel="noopener noreferrer"&gt;GCP&lt;/a&gt; just in order to setup a tiny serverless function either.&lt;/p&gt;




&lt;h1&gt;
  
  
  Solution
&lt;/h1&gt;

&lt;p&gt;My solution was to turn to &lt;a href="https://docs.gitlab.com/ce/ci/" rel="noopener noreferrer"&gt;GitLab's awesome CI/CD-as-a-service feature&lt;/a&gt; - which I know very well already and have used in many other personal / work project.&lt;br&gt;
This feature, in a nutshell, allows you to define a &lt;code&gt;.yml&lt;/code&gt; file with your CI/CD pipeline configuration in a repo, and have set it to run in any automatic schedule (or with a trigger). A pipeline is composed of jobs, which run any script you need in any container.&lt;/p&gt;

&lt;p&gt;So in that case, all we need to do is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a project in GitLab.&lt;/li&gt;
&lt;li&gt;Code the task that we want to perform (in any language / framework).&lt;/li&gt;
&lt;li&gt;Set up the GitLab's project's CI/CD so that it will run the correct job with your desired settings (schedule, webhook, manually, etc.).&lt;/li&gt;
&lt;li&gt;Move on with your (easier) life.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Create a GitLab project
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Sign up if you haven't already, and go to &lt;a href="https://gitlab.com/projects/new#blank_project" rel="noopener noreferrer"&gt;https://gitlab.com/projects/new#blank_project&lt;/a&gt; in order to create a new project.&lt;/li&gt;
&lt;li&gt;Fill in the relevant details and create the project.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu3pdi1mqeiq403sifb28.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu3pdi1mqeiq403sifb28.png" alt="Creating a new project on gitlab.com"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Add the task itself
&lt;/h2&gt;

&lt;p&gt;For this example, let's create this &lt;code&gt;run-me.js&lt;/code&gt; file:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hi there, I ran and made your life easier!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can either clone the repo that you've just created and commit-push the task's file from your computer, or easily enough add it straight into gitlab.com using their nice "Web IDE":&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn9owhbeofq9wrod7k6w3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn9owhbeofq9wrod7k6w3.png" alt="Creating a new file straight from gitlab.com"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fje7ixm1xn4jocgosp0rb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fje7ixm1xn4jocgosp0rb.png" alt="Entering the task's code on gitlab.com"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Commit the changes, and now you have the task's code in the repo - this code will be available inside the container that will run the pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set up CI/CD to run your code as you wish
&lt;/h2&gt;

&lt;p&gt;The same way you did in the previous step, add another file called &lt;code&gt;.gitlab-ci.yml&lt;/code&gt;.&lt;br&gt;
GitLab offer some useful templates, but in our case, we'll just go ahead with a blank file, and in it add your definition for container image, and what to run in it (including the task you wrote):&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node:alpine&lt;/span&gt;
&lt;span class="na"&gt;run-task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;schedules&lt;/span&gt;
 &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;node ./run-me.js&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fezo9uq0d2wsmi4r1k6xm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fezo9uq0d2wsmi4r1k6xm.png" alt="Creating a new  raw `.gitlab-ci.yml` endraw  file on gitlab.com"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Notes:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Here I chose &lt;code&gt;node:alpine&lt;/code&gt; as the container. Why? &lt;code&gt;node&lt;/code&gt; because my code is in Node.js, and &lt;code&gt;:alpine&lt;/code&gt; because it's light and fast (quicker to launch). Why not? You may not work with Node.js, and in &lt;a href="https://alpinelinux.org/" rel="noopener noreferrer"&gt;Alpine Linux&lt;/a&gt; you might need to install additional tools / programs that do not come out-of-the-box.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;only:&lt;/code&gt; part makes sure that our job only runs in scheduled runs, and not in any push to &lt;code&gt;master&lt;/code&gt; (which is the default).&lt;/li&gt;
&lt;li&gt;Whatever is under &lt;code&gt;script:&lt;/code&gt; are commands that you run in a &lt;code&gt;bash&lt;/code&gt; (in Alpine it's &lt;code&gt;sh&lt;/code&gt;), already inside the directory of the cloned repo. This is already a script by itself, so if you're a &lt;code&gt;bash&lt;/code&gt; expert, go ahead and do what you need directly there.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For testing, you can go to &lt;a href="https://gitlab.com/YOUR_GITLAB_NAME/YOUR_PROJECT/-/pipelines/new" rel="noopener noreferrer"&gt;https://gitlab.com/YOUR_GITLAB_NAME/YOUR_PROJECT/-/pipelines/new&lt;/a&gt; and (provided that you commit to &lt;code&gt;master&lt;/code&gt;) start a new pipeline manually.&lt;/p&gt;

&lt;p&gt;After running, you can go to &lt;a href="https://gitlab.com/YOUR_GITLAB_NAME/YOUR_PROJECT/-/pipelines" rel="noopener noreferrer"&gt;https://gitlab.com/YOUR_GITLAB_NAME/YOUR_PROJECT/-/pipelines&lt;/a&gt;, and see a new line with the pipeline that has started:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4txt0t7fzq2pl40rui5s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4txt0t7fzq2pl40rui5s.png" alt="Running pipeline on gitlab.com"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The pipeline will fetch and run the &lt;code&gt;node:alpine&lt;/code&gt; image, and then execute our code from &lt;code&gt;run-me.js&lt;/code&gt; inside it 💪.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdxxiere70wzya037mihk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdxxiere70wzya037mihk.png" alt="Log of a pipeline's job on gitlab.com"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is already awesome, as you can now run any code inside a container in the cloud!&lt;/p&gt;

&lt;p&gt;In order to schedule it, go to &lt;a href="https://gitlab.com/YOUR_GITLAB_NAME/YOUR_PROJECT/-/pipeline_schedules/new" rel="noopener noreferrer"&gt;https://gitlab.com/YOUR_GITLAB_NAME/YOUR_PROJECT/-/pipeline_schedules/new&lt;/a&gt;, and create a new schedule for this repo's pipeline.&lt;br&gt;
In this example, let's say we want it to be Sunday to Friday at 7:30 AM, which means setting a custom interval pattern as &lt;code&gt;30 7 * * 0–5&lt;/code&gt;. If you need help with cron syntax, check &lt;a href="https://crontab.guru" rel="noopener noreferrer"&gt;https://crontab.guru&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiyixi4mro3ot7fogpup6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiyixi4mro3ot7fogpup6.png" alt="Pipeline schedule configuration on gitlab.com"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Save the pipeline schedule and you can expect it to run surely and independently ☁️.&lt;/p&gt;




&lt;h1&gt;
  
  
  Notes
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://about.gitlab.com/pricing/" rel="noopener noreferrer"&gt;GitLab's free plan&lt;/a&gt; includes 400 CI/CD minutes per month, which should be more than enough for simple tasks running on a lean container (such as Alpine). For example the code in this example takes 22 seconds to run, which means it has ~1,200 runs per month before exceeding the 400 minutes quota. If you need more, you can either upgrade your plan, or &lt;a href="https://docs.gitlab.com/runner/install/index.html" rel="noopener noreferrer"&gt;setup your own CI/CD runner&lt;/a&gt; anywhere you want.&lt;/li&gt;
&lt;li&gt;You may want to expose the failure / success of your code run by exiting with a code. So for example, if your code exits with anything that's not 0, it will be pronounced a failure, and from there you can monitor and even get notified about.&lt;/li&gt;
&lt;li&gt;Suspending the schedule can be easily done by deactivating the pipeline's schedule.&lt;/li&gt;
&lt;li&gt;GitLab CI/CD supports any publicly available docker image, and uses &lt;a href="https://hub.docker.com/" rel="noopener noreferrer"&gt;Docker Hub&lt;/a&gt; by default. So either use one from there (choose carefully), or even &lt;a href="https://docs.docker.com/docker-hub/publish/publish/" rel="noopener noreferrer"&gt;publish your own&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;You can have more than one task in one repo - you'll need to play around with different branches, or &lt;a href="https://docs.gitlab.com/ee/ci/yaml/" rel="noopener noreferrer"&gt;configure your .gitlab-ci.yml properly&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Refer to &lt;a href="https://docs.gitlab.com/ee/ci/" rel="noopener noreferrer"&gt;GitLab CI/CD's extensive documentation&lt;/a&gt; - you can achieve really awesome things with it (especially for bigger serious projects).&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>docker</category>
      <category>gitlab</category>
      <category>automation</category>
      <category>cicd</category>
    </item>
  </channel>
</rss>
