<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Cron on blog.iankulin.com</title><link>https://blog.iankulin.com/tags/cron/</link><description>Recent content in Cron on blog.iankulin.com</description><generator>Hugo</generator><language>en-AU</language><lastBuildDate>Mon, 15 Jul 2024 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.iankulin.com/tags/cron/index.xml" rel="self" type="application/rss+xml"/><item><title>User environment variables are not available in cron</title><link>https://blog.iankulin.com/user-environment-variables-are-not-available-in-cron/</link><pubDate>Mon, 15 Jul 2024 00:00:00 +0000</pubDate><guid>https://blog.iankulin.com/user-environment-variables-are-not-available-in-cron/</guid><description>&lt;p&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2024-07-02-at-4.13.13-pm.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m used to using the &lt;code&gt;docker-compose.yaml&lt;/code&gt; or &lt;code&gt;dockerfile&lt;/code&gt; to set environment variables for containers running my apps, but ran into an issue recently where the variable seemed to be set some of the time, but at others it didn&amp;rsquo;t appear to exist.&lt;/p&gt;
&lt;p&gt;I had a script set to run by &lt;code&gt;cron&lt;/code&gt; inside the container, and it turns out that the environment variables set for the container are available in the user space, but not in &lt;code&gt;cron&lt;/code&gt;, even if running with that user&amp;rsquo;s permissions. This is probably old news to established Linux users but it threw me for a while. I&amp;rsquo;d &lt;code&gt;exec&lt;/code&gt; into the container and the script would work perfectly, then wait another minute for &lt;code&gt;cron&lt;/code&gt; to run it and it would fail 🤦‍♀️ It was exasperated by my discovery that I didn&amp;rsquo;t know how to console.log debug from inside a container cron job as well - the subject of an earlier post.&lt;/p&gt;
&lt;p&gt;Once I&amp;rsquo;d narrowed it down to this issue and googleconfirmed it, I didn&amp;rsquo;t really come up with an elegant solution either. You may think &amp;ldquo;buy hey, everything in Linux is a file, it must be in proc somewhere&amp;rdquo;, and you&amp;rsquo;d be right, sort of.&lt;/p&gt;
&lt;p&gt;In Linux, to see your own environment variables, you type in &lt;code&gt;env&lt;/code&gt;. I think this probably works by grabbing them from &lt;code&gt;proc&lt;/code&gt; under &lt;code&gt;/proc/&amp;lt;PID&amp;gt;/environ&lt;/code&gt; where &lt;PID&gt; is the process id of the shell. We can get our own process id with the &lt;code&gt;ps&lt;/code&gt; command. If we&amp;rsquo;re the root user (which I am in my container) we can see &lt;em&gt;someone else&amp;rsquo;s&lt;/em&gt; process ids with &lt;code&gt;ps -u &amp;lt;username&amp;gt;&lt;/code&gt;, get the process id for the shell and look in proc. So I tried that from the cron script - it turns out no.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2024-07-02-at-6.51.16-pm.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;I could see them, but it didn&amp;rsquo;t include the environment variable passed in from Docker that was available at the entry point. This is all a bit weird to me - I&amp;rsquo;m not sure why we&amp;rsquo;re the same user, with the same permissions but with a new seperate environment. I guess there is a reason, it&amp;rsquo;s just not apparent to me.&lt;/p&gt;
&lt;h3 id="the-hack"&gt;The Hack&lt;/h3&gt;
&lt;p&gt;To get around this, I now save the environment variable I&amp;rsquo;m interested in to a file in the script that runs at the entry point:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#616e87;font-style:italic"&gt;# Save the environment variable IMAGE_URL into&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#616e87;font-style:italic"&gt;# a file for later use in the cron script&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;env &lt;span style="color:#81a1c1"&gt;|&lt;/span&gt; grep IMAGE_URL &lt;span style="color:#81a1c1"&gt;&amp;gt;&lt;/span&gt; image_url&lt;span style="color:#81a1c1"&gt;.&lt;/span&gt;txt
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then in my script that is run by cron, I reconstitute it from the file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#616e87;font-style:italic"&gt;# Read the file saved by the entry point script&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#616e87;font-style:italic"&gt;# and extract the environment variable&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#81a1c1;font-weight:bold"&gt;while&lt;/span&gt; IFS&lt;span style="color:#81a1c1"&gt;=&lt;/span&gt;&lt;span style="color:#a3be8c"&gt;&amp;#39;=&amp;#39;&lt;/span&gt; read &lt;span style="color:#81a1c1"&gt;-&lt;/span&gt;r key value&lt;span style="color:#eceff4"&gt;;&lt;/span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;if&lt;/span&gt; &lt;span style="color:#eceff4"&gt;[[&lt;/span&gt; &lt;span style="color:#81a1c1"&gt;$&lt;/span&gt;key &lt;span style="color:#81a1c1"&gt;==&lt;/span&gt; &lt;span style="color:#a3be8c"&gt;&amp;#34;IMAGE_URL&amp;#34;&lt;/span&gt; &lt;span style="color:#eceff4"&gt;]];&lt;/span&gt; then
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#81a1c1;font-weight:bold"&gt;export&lt;/span&gt; &lt;span style="color:#a3be8c"&gt;&amp;#34;$key=$value&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; fi
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;done &lt;span style="color:#81a1c1"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#a3be8c"&gt;&amp;#34;/image_url.txt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That works fine. Software testers will be looking at this solution thinking &amp;ldquo;What about the case where the environment variable isn&amp;rsquo;t set, but the file from the last run is still there?&amp;rdquo; Worry not, bug finding person. It&amp;rsquo;s a container so everything&amp;rsquo;s ephemeral. The file with the environment variable can only be there on runs when that environment variable has been set.&lt;/p&gt;</description></item><item><title>Outputting to the console, in Docker, from a cron job</title><link>https://blog.iankulin.com/outputting-to-the-console-in-docker-from-a-cron-job/</link><pubDate>Mon, 08 Jul 2024 00:00:00 +0000</pubDate><guid>https://blog.iankulin.com/outputting-to-the-console-in-docker-from-a-cron-job/</guid><description>&lt;p&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2024-07-02-at-3.48.02-pm.jpg" alt=""&gt;&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re googling this exact title, you&amp;rsquo;re probably bumping your head against the same things I was today. I was debugging a completely different project, and needed to print to the console, from a &lt;code&gt;cron&lt;/code&gt; job, in a Docker container. Turns out this isn&amp;rsquo;t as straightforward as I thought.&lt;/p&gt;
&lt;h3 id="foreground-cron"&gt;Foreground cron&lt;/h3&gt;
&lt;p&gt;Before you even get to the problem space, here&amp;rsquo;s a tip. If you want to have a cron job running in a container, start &lt;code&gt;cron&lt;/code&gt; in the foreground. If you do not, Docker realises nothing is going on, and exits. If you want to keep the container active so your &lt;code&gt;cron&lt;/code&gt; jobs get a chance to execute, then start it in the foreground.&lt;/p&gt;
&lt;h3 id="stdout"&gt;stdout&lt;/h3&gt;
&lt;p&gt;I always think about &lt;code&gt;stdout&lt;/code&gt; as being the console, but I guess at one time it was probably a teletype printer, and for &lt;code&gt;cron&lt;/code&gt;, &lt;a href="https://askubuntu.com/questions/1454389/where-does-the-users-cron-output-go-to-by-default-on-ubuntu"&gt;apparently it&amp;rsquo;s an email to the user&lt;/a&gt;. So me directing the output of the command I&amp;rsquo;m running in crontab to stdout is not helpful. It turns out you need something like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;* * * * * /script.sh &amp;gt; /proc/1/fd/1 2&amp;gt;&amp;amp;1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;a href="https://github.com/moby/moby/issues/19616#issuecomment-174492543"&gt;There&amp;rsquo;s some good Linuxy reason for this&lt;/a&gt; - &lt;code&gt;/proc/1/fd/1&lt;/code&gt; is the standard output of a particular process which happens to be the process for the entry point of the container or some such thing,&lt;/p&gt;
&lt;p&gt;If you are not familiar with &lt;code&gt;cron&lt;/code&gt;, there are going to be much better explanations than this, but it&amp;rsquo;s a mechanism for running jobs at various times. It uses a file, called the &lt;code&gt;crontab&lt;/code&gt; to define these. Each of the asterisks above are spots where we can define the minute, hour, day, etc that the job runs by entering a number. If they are all asterisks then we are saying &amp;lsquo;run this every minute&amp;rsquo;. Following that is just the command, which in this case is run &lt;code&gt;/script.sh&lt;/code&gt; and send the output and error output to this proc file which happens to be the console.&lt;/p&gt;
&lt;p&gt;Other gotchas when working with cron is which user it&amp;rsquo;s running as (so permission problems) and where it&amp;rsquo;s running from (don&amp;rsquo;t use relative file paths).&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/IanKulin/cron-docker-output"&gt;Example project on GutHub&lt;/a&gt;&lt;/p&gt;</description></item></channel></rss>