{"id":2557,"date":"2024-03-14T17:32:50","date_gmt":"2024-03-14T23:32:50","guid":{"rendered":"https:\/\/mrguitar.net\/?p=2557"},"modified":"2024-06-12T16:21:15","modified_gmt":"2024-06-12T22:21:15","slug":"rebuilding-container-images-with-systemd-timers-podman","status":"publish","type":"post","link":"https:\/\/mrguitar.net\/?p=2557","title":{"rendered":"Rebuilding Container Images with systemd timers &#038; podman"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"258\" src=\"https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/03\/project_math-1024x258.png\" alt=\"\" class=\"wp-image-2559\" srcset=\"https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/03\/project_math-1024x258.png 1024w, https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/03\/project_math-300x76.png 300w, https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/03\/project_math-768x193.png 768w, https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/03\/project_math-1536x387.png 1536w, https:\/\/mrguitar.net\/wp-content\/uploads\/2024\/03\/project_math-2048x516.png 2048w\" sizes=\"auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/figure>\n\n\n\n<p>In general, it&#8217;s considered a best practice when running containers to ensure that the images are being rebuilt on a regular basis to pickup security\/bug fixes. In a real production environment, it&#8217;s common to use something like jenkins, github actions, or some type of automation or CI\/CD workflow to keep the images fresh. &#8230;.but here at my house, I only have a single server that runs containers and my use case doesn&#8217;t really warrant a more serious CI\/CD setup. This blog will show you how to setup a simple &#8220;perpetual motion&#8221; machine to automatically rebuild container images and then auto-update them. It&#8217;s also pretty easy to setup and works great too!<\/p>\n\n\n\n<!--more-->\n\n\n\n<p>First, let&#8217;s understand that podman can <a href=\"https:\/\/docs.podman.io\/en\/latest\/markdown\/podman-auto-update.1.html\" data-type=\"link\" data-id=\"https:\/\/docs.podman.io\/en\/latest\/markdown\/podman-auto-update.1.html\" target=\"_blank\" rel=\"noreferrer noopener\">auto update containers<\/a> based on a registry tag or using the local image store. Most of the time, I rely on new versions landing in the registry, but since this is a single server where we&#8217;re rebuilding, I think it makes more since to use the local storage option. To use auto-updates we need to label the container with <code>--label io.containers.autoupdate=local<\/code> If you want to read more on this subject, I recommend <a href=\"https:\/\/www.redhat.com\/sysadmin\/podman-auto-updates-rollbacks\" data-type=\"link\" data-id=\"https:\/\/www.redhat.com\/sysadmin\/podman-auto-updates-rollbacks\" target=\"_blank\" rel=\"noreferrer noopener\">this blog post<\/a>. Once this is in place, enable the auto-updates timer and adjust the timer unit to your desired time to run. <code>systemctl enable --now podman-auto-update.timer<\/code>.<\/p>\n\n\n\n<p>I prefer using Quadlets to define my applications. Notice the line below invokes <code>AutoUpdate=local<\/code><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cat \/etc\/containers\/systemd\/caddy.container\n\n&#91;Unit]\nDescription=Caddy Quadlet\n\n&#91;Container]\nImage=localhost\/caddy:latest\nContainerName=caddy\nAutoUpdate=local\nEnvironmentFile=\/etc\/containers.environment\nVolume=caddy-data.volume:\/data\nVolume=caddy-config.volume:\/config\nVolume=\/etc\/Caddyfile:\/etc\/caddy\/Caddyfile:Z\nPublishPort=80:80\nPublishPort=443:443\n\n&#91;Service]\nRestart=always\nTimeoutStartSec=900\n\n&#91;Install]\nWantedBy=multi-user.target default.target\n<\/code><\/pre>\n\n\n\n<p>The <code>caddy.container<\/code> file above will ensure that this container is always running, and the <code>podman-auto-update.timer<\/code> is set to check for nightly updates. Honestly that&#8217;s pretty amazing on it&#8217;s own &#8211; especially if you remember the early days of Linux containers. From here all we need to do is create unit files to rebuild the image and automatically run it.<\/p>\n\n\n\n<p> This unit will basically just run podman build and create our image. A nice option in podman is the &#8211;pull which just like docker will grab the latest image from the registry. I chose to run a prune command to prevent the system storage from filling up w\/ too many builds. Some people may not want the prune line.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># \/etc\/systemd\/system\/caddy-build.service\n&#91;Unit]\nDescription=Rebuild the caddy container image\n\n&#91;Service]\nType=oneshot\nExecStart=\/usr\/bin\/podman build \u2013pull -f \/etc\/caddy\/caddy.cf -t caddy:latest\nExecStart=\/usr\/bin\/podman image prune -f<\/code><\/pre>\n\n\n\n<p>From here, we just need to create a timer unit w\/ the same name as the unit above and pick a time for it to run. I chose to run this weekly as it&#8217;s not super urgent for me to rebuild this frequently. For my situation monthly would be fine and I may tweak this over time as I&#8217;m still relatively new to using caddy.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># \/etc\/systemd\/system\/caddy-build.timer\n&#91;Unit]\nDescription=Rebuild caddy once a week\n\n&#91;Timer]\nOnCalendar=weekly\nAccuracySec=1h\nPersistent=true\nRandomizedDelaySec=100min\n\n&#91;Install]\nWantedBy=timers.target<\/code><\/pre>\n\n\n\n<p>Simply enable the above timer with <code>systemctl enable --now caddy-build.timer<\/code> and your perpetual motion machine will be set in motion! I have no doubts that using a more modern setup like github actions or gitlab runner would enable something smarter. I do plan to move to this model at some point, but for now this seems to be working well enough and it was painless to setup. <\/p>\n\n\n\n<p class=\"has-black-color has-text-color has-link-color wp-elements-a38949d1341867a7f85c84bfb22ac6c5\"><strong>UPDATE!<\/strong> I also added a simple healthcheck to this setup to ensure the update is functioning. There may be a better way to do this, but I just added a handler that responds OK in my Caddyfile:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>        @healthcheck host healthcheck.mydomain.com\n        handle @healthcheck {\n                respond \"OK\" 200\n        }\n<\/code><\/pre>\n\n\n\n<p>Then a simple script to verify Caddy is responding and <code>COPY<\/code> this inside the containerfile when it&#8217;s built:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cat healthcheck.sh \n#!\/bin\/sh\ntest \"$(curl -s https:\/\/healthcheck.mydomain.com)\" = OK\n<\/code><\/pre>\n\n\n\n<p>Then finally add these lines to the quadlet file above:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>HealthCmd=\/healthcheck.sh\nHealthInterval=2m\nHealthOnFailure=kill\nHealthRetries=3\n<\/code><\/pre>\n\n\n\n<p>i wouldn&#8217;t say this gives us perfect resiliency, but it does add a good layer. <a href=\"https:\/\/www.redhat.com\/sysadmin\/podman-edge-healthcheck\" data-type=\"link\" data-id=\"https:\/\/www.redhat.com\/sysadmin\/podman-edge-healthcheck\" target=\"_blank\" rel=\"noreferrer noopener\">This is a good blog post<\/a> if you want more details. One thing I don&#8217;t have working yet is auto-rollback and I believe I need to switch to a registry for this to work. <\/p>\n\n\n\n<p>At first, I tried googling for a similar setup and couldn&#8217;t find anything. I&#8217;m sharing this in case it&#8217;s useful for others, so please copy\/paste and tweak for your own images and please leave any recommendations in the comments for improvements. I&#8217;m sure others will benefit. Cheers!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In general, it&#8217;s considered a best practice when running containers to ensure that the images are being rebuilt on a regular basis to pickup security\/bug fixes. In a real production environment, it&#8217;s common to use something like jenkins, github actions, or some type of automation or CI\/CD workflow to keep the images fresh. &#8230;.but here &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/mrguitar.net\/?p=2557\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Rebuilding Container Images with systemd timers &#038; podman&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[6],"tags":[124,122,106,123],"class_list":["post-2557","post","type-post","status-publish","format-standard","hentry","category-open-sourcenerd-stuff","tag-auto-update","tag-caddy","tag-podman","tag-systemd"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/mrguitar.net\/index.php?rest_route=\/wp\/v2\/posts\/2557","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mrguitar.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mrguitar.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mrguitar.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mrguitar.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2557"}],"version-history":[{"count":5,"href":"https:\/\/mrguitar.net\/index.php?rest_route=\/wp\/v2\/posts\/2557\/revisions"}],"predecessor-version":[{"id":2573,"href":"https:\/\/mrguitar.net\/index.php?rest_route=\/wp\/v2\/posts\/2557\/revisions\/2573"}],"wp:attachment":[{"href":"https:\/\/mrguitar.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2557"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mrguitar.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2557"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mrguitar.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2557"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}