{"id":9798,"date":"2022-02-08T16:00:34","date_gmt":"2022-02-08T10:30:34","guid":{"rendered":"https:\/\/opstree.com\/blog\/\/?p=9798"},"modified":"2022-02-08T16:00:34","modified_gmt":"2022-02-08T10:30:34","slug":"learn-the-hacks-for-running-custom-scripts-at-spot-termination","status":"publish","type":"post","link":"https:\/\/opstree.com\/blog\/2022\/02\/08\/learn-the-hacks-for-running-custom-scripts-at-spot-termination\/","title":{"rendered":"Learn the Hacks for Running Custom Scripts at Spot Termination"},"content":{"rendered":"\n<p>Nowadays, it is very common to run applications on Spot instances. In this scenario, where a spot instance could be terminated at any point of time because of AWS pulling back their resource or ASG Scale-In incident, we need to have something in place to handle the termination smoothly so that we can complete our final tasks before the system shutdown. It could be executing some scripts, unmounting some storage device, shipping final log files to S3, or uploading cache data in a centralized server like Redis.<br>Today, I will attempt to cater to this problem.<br><br>First of all, let&#8217;s think of trying to run a custom script prior to shutdown in our local system. If everything works fine, the same would be applicable for ec2 spot instances too.<\/p>\n\n\n\n<!--more-->\n\n\n\n<p>I will be using a Ubuntu 20 machine that uses <em>systemd <\/em>as the service manager for this entire blog (works for Ubuntu 16\/18\/20\/22 as well).<br><br>As all of you might know, we can add our custom service file in the \/etc\/systemd\/system\/ location and install it in any of the target levels to run your program\/script as a service.<br><br>Below is an example of a service file that can run your custom script prior to shutdown, and will hold the shutdown process until your script is completed.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#091;root@ss ~]# cat \/etc\/systemd\/system\/run-pre-shutdown.service\n&#091;Unit]\nDescription=Run custom task prior shutdown\nDefaultDependencies=no\nBefore=shutdown.target\n\n&#091;Service]\nType=oneshot\nExecStart=&lt;your script here&gt;\nTimeoutStartSec=0\n\n&#091;Install]\nWantedBy=shutdown.target\n<\/code><\/pre>\n\n\n\n<p>So, this script basically tells the system to run the <code>ExecStart<\/code> to run before shutdown. The&nbsp; <code>TimeoutStartSec<\/code> directive tells the time the system will wait for the process to start (or completed in this case). One can read details about the directives <a href=\"https:\/\/www.digitalocean.com\/community\/tutorials\/understanding-systemd-units-and-unit-files\" target=\"_blank\" rel=\"noopener\">here<\/a>.<br><br>Next, make sure you have executable permissions on the <strong>run-pre-shutdown.service<\/strong> and the custom script mentioned in <code>ExecStart<\/code>.<br>Then run <code>systemctl daemon-reload<\/code> followed by <code>systemctl enable run-pre-shutdown.service<\/code>.<br><br>So far so good, but this script won&#8217;t be able to access the internet or do a curl and hence will not be able to ship logs to the S3 bucket or put data into Redis. This is because the network will be already shut down when <em>systemd<\/em> reaches to execute this script. To handle this we can use a <em>systemd<\/em> unit file similar to this  below. This unit file ships data from the <code>\/var\/log\/<\/code> directory in your system to your S3 bucket. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ss@ubuntumini:\/etc\/systemd\/system$ cat run-before-shutdown.service\n&#091;Unit]\nDescription=Send Logs\nRequires=network-online.target\nAfter=network.target\n\n&#091;Service]\nType=oneshot\nRemainAfterExit=yes\nExecStop=\/usr\/bin\/aws s3 --region ap-south-1 sync \/var\/log\/ s3:\/\/bucket-name\/path-to-folder\/\n\n\n&#091;Install]\nWantedBy=network.target\n<\/code><\/pre>\n\n\n\n<p>Let&#8217;s break down the parts of this unit file.<br><br>The shutdown ordering of units in <em>systemd<\/em> is the reverse of the startup order. Hence, any unit that is ordered <code>After=network.target<\/code> can be sure that it is stopped before the network is shut down if the system is powered off\/terminated. And our purpose is solved here.<br><br><strong>Note<\/strong>: It is not mandatory here to install it under <strong>network.target<\/strong>, we can also specify as <code>WantedBy=multi-user.target<\/code><br><br>For better understanding, I will just rename the file name, since <em>systemd<\/em> orders units in the alphabet order as well, I will rename it to <code>aa-run-before-shutdown.service<\/code><br><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>root@ubuntumini:\/etc\/systemd\/system# mv run-before-shutdown.service <strong>aa-run-before-shutdown.service<\/strong>\n\nroot@ubuntumini:\/etc\/systemd\/system# systemctl daemon-reload\nroot@ubuntumini:\/etc\/systemd\/system# systemctl enable aa-run-before-shutdown.service\nCreated symlink \/etc\/systemd\/system\/network.target.wants\/aa-run-before-shutdown.service \u2192 \/etc\/systemd\/system\/aa-run-before-shutdown.service.\n\nroot@ubuntumini:\/etc\/systemd\/system# systemctl start aa-run-before-shutdown.service\nroot@ubuntumini:\/etc\/systemd\/system# systemctl status aa-run-before-shutdown.service\n\u25cf aa-run-before-shutdown.service - Send Logs\n     Loaded: loaded (\/etc\/systemd\/system\/aa-run-before-shutdown.service; enabled; vendor preset: enabled)\n     <strong>Active<\/strong>: active (exited) since Fri 2022-02-04 06:35:19 UTC; 2s ago\n\nFeb 04 06:35:19 ubuntumini systemd&#091;1]: Finished Send Logs.\nroot@ubuntumini:\/etc\/systemd\/system#<\/code><\/pre>\n\n\n\n<p class=\"has-bright-blue-color has-text-color\">Note:&nbsp; It is mandatory that the service is Started and the status is Active as above.<\/p>\n\n\n\n<p><strong>[optional]:<\/strong> Now if you run the command &#8211; <code>systemctl list-dependencies --after shutdown.target<\/code> &nbsp;we will be able to see the service with <strong>green <\/strong>(meaning active state) at the top.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"781\" height=\"182\" src=\"https:\/\/opstree.com\/blog\/\/wp-content\/uploads\/2022\/02\/image.png?w=781\" alt=\"\" class=\"wp-image-9811\" \/><\/figure>\n\n\n\n<p><br>In our case, make sure you have <strong><em>awscli<\/em><\/strong> installed and have Access\/Secret keys configured with proper permissions to Get\/Put on the S3 bucket.<br><br>Next, let&#8217;s shut down the system to see this working.<br><br><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/lh3.googleusercontent.com\/kP_6pyRLAQbW1Oik53bpp2swkwZ7-lBsAVPfLHFvbMcrFjJ2mUNaEkwy_Kz9ZmQ6bn2NPsI0eINDNhXAme0CGBOxzx7XhMN8nZRmqVM5pD6VCrXCernkUMVgoBHf9AzZyuzHntAB\" width=\"625\" height=\"464\"><\/p>\n\n\n\n<p>You will see a job is running that has halted the shutdown process.&nbsp; Finally when the logs are sent the process will be stopped, the shutdown will be complete. Check your S3 bucket and the files should be there.<br><br><br>The same procedure can be applied on a Spot instance and it works absolutely perfectly. And the entire steps can be automated via <strong>Ansible<\/strong> as well.<br><br><br><strong>Challenges<\/strong>:-<\/p>\n\n\n\n<ul><li>Big Logs files take longer to upload, so we should zip the files before sending to S3.<\/li><\/ul>\n\n\n\n<p>For this one can use a utility like <a href=\"https:\/\/linuxize.com\/post\/gzip-command-in-linux\/\" target=\"_blank\" rel=\"noopener\">gzip<\/a> or <a href=\"https:\/\/linux.die.net\/man\/8\/logrotate\" target=\"_blank\" rel=\"noopener\">logrotate<\/a> to zip the files before sending them to S3.<\/p>\n\n\n\n<p>And we will have to add one more line in our service file:-<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ExecStop=\/usr\/bin\/gzip -r \/var\/log\/apt\/\nExecStop=\/usr\/bin\/aws s3 --region ap-south-1 sync \/var\/log\/apt\/ s3:\/\/your-bucket-name\/newfolder\/<\/code><\/pre>\n\n\n\n<p>Gzip has almost had a great compression ratio (reduce file size up to 20 times) and even a 1GB file will be reduced to a 50MB .gz file which can be very easily uploaded in S3 in a limited time.<br><\/p>\n\n\n\n<ul><li>AWS recommended approach &#8211;<br><br>If your system needs to run scripts for graceful shutdown that takes much much longer time than this, then you can follow these docs &#8211;<\/li><\/ul>\n\n\n\n<p><strong>1.<\/strong>&nbsp; Scrapping an AWS API which returns the termination time 2 mins prior and you have 2 mins to handle and make all necessary preparation before shutdown.<a href=\"https:\/\/aws.amazon.com\/blogs\/aws\/new-ec2-spot-instance-termination-notices\/\" target=\"_blank\" rel=\"noopener\">https:\/\/aws.amazon.com\/blogs\/aws\/new-ec2-spot-instance-termination-notices\/<\/a><\/p>\n\n\n\n<p><strong>2.<\/strong> Since, scrapping an endpoint continuously from within the system is a resource-consuming process, it is recommended to use AWS EventsBridge and SNS to send notifications.<\/p>\n\n\n\n<p><br>Hope you found the article useful!<br><br>Demo &#8211;<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-rich is-provider-embed-handler wp-block-embed-embed-handler wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<span class=\"embed-youtube\" style=\"text-align:center; display: block;\"><iframe loading=\"lazy\" class=\"youtube-player\" width=\"840\" height=\"473\" src=\"https:\/\/www.youtube.com\/embed\/Fk42rqaQld0?version=3&#038;rel=1&#038;showsearch=0&#038;showinfo=1&#038;iv_load_policy=1&#038;fs=1&#038;hl=en-US&#038;autohide=2&#038;wmode=transparent\" allowfullscreen=\"true\" style=\"border:0;\" sandbox=\"allow-scripts allow-same-origin allow-popups allow-presentation allow-popups-to-escape-sandbox\"><\/iframe><\/span>\n<\/div><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p><strong style=\"font-weight:bold;\">Blog Pundit: <\/strong><a href=\"https:\/\/opstree.com\/blog\/\/author\/naveenverma023\/\"><strong>Naveen Verma<\/strong><\/a> <\/p>\n\n\n\n<p><a href=\"https:\/\/www.opstree.com\/contact-us?utm_source=blog&amp;utm_medium=wordpress+&amp;utm_campaign=Learn-the-hacks-for-running-custom-scripts-at-spot-termination\" target=\"_blank\" rel=\"noreferrer noopener\"><strong>Opstree<\/strong> <\/a>is an End to End DevOps solution provider<\/p>\n\n\n\n<div class=\"wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex\">\n<div class=\"wp-block-button is-style-fill\"><a class=\"wp-block-button__link\" href=\"https:\/\/www.opstree.com\/contact-us\" target=\"_blank\" rel=\"noreferrer noopener\">CONTACT US<\/a><\/div>\n<\/div>\n\n\n\n<p class=\"has-text-align-center\"><strong>Connect Us <\/strong><\/p>\n\n\n\n<ul class=\"wp-block-social-links aligncenter is-content-justification-right is-layout-flex wp-container-core-social-links-is-layout-1 wp-block-social-links-is-layout-flex\"><li class=\"wp-social-link wp-social-link-linkedin  wp-block-social-link\"><a href=\"https:\/\/www.linkedin.com\/company\/opstree-solutions\" class=\"wp-block-social-link-anchor\" target=\"_blank\" rel=\"noopener\"><svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" version=\"1.1\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z\"><\/path><\/svg><span class=\"wp-block-social-link-label screen-reader-text\">LinkedIn<\/span><\/a><\/li>\n\n<li class=\"wp-social-link wp-social-link-youtube  wp-block-social-link\"><a href=\"https:\/\/www.youtube.com\/channel\/UCeLma6SpNYH7jjYKSBNSexw\" class=\"wp-block-social-link-anchor\" target=\"_blank\" rel=\"noopener\"><svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" version=\"1.1\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z\"><\/path><\/svg><span class=\"wp-block-social-link-label screen-reader-text\">YouTube<\/span><\/a><\/li>\n\n<li class=\"wp-social-link wp-social-link-github  wp-block-social-link\"><a href=\"https:\/\/github.com\/OpsTree\" class=\"wp-block-social-link-anchor\" target=\"_blank\" rel=\"noopener\"><svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" version=\"1.1\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z\"><\/path><\/svg><span class=\"wp-block-social-link-label screen-reader-text\">GitHub<\/span><\/a><\/li>\n\n<li class=\"wp-social-link wp-social-link-facebook  wp-block-social-link\"><a href=\"https:\/\/www.facebook.com\/opstree\" class=\"wp-block-social-link-anchor\" target=\"_blank\" rel=\"noopener\"><svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" version=\"1.1\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z\"><\/path><\/svg><span class=\"wp-block-social-link-label screen-reader-text\">Facebook<\/span><\/a><\/li>\n\n<li class=\"wp-social-link wp-social-link-medium  wp-block-social-link\"><a href=\"https:\/\/medium.com\/buildpiper\" class=\"wp-block-social-link-anchor\" target=\"_blank\" rel=\"noopener\"><svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" version=\"1.1\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M20.962,7.257l-5.457,8.867l-3.923-6.375l3.126-5.08c0.112-0.182,0.319-0.286,0.527-0.286c0.05,0,0.1,0.008,0.149,0.02 c0.039,0.01,0.078,0.023,0.114,0.041l5.43,2.715l0.006,0.003c0.004,0.002,0.007,0.006,0.011,0.008 C20.971,7.191,20.98,7.227,20.962,7.257z M9.86,8.592v5.783l5.14,2.57L9.86,8.592z M15.772,17.331l4.231,2.115 C20.554,19.721,21,19.529,21,19.016V8.835L15.772,17.331z M8.968,7.178L3.665,4.527C3.569,4.479,3.478,4.456,3.395,4.456 C3.163,4.456,3,4.636,3,4.938v11.45c0,0.306,0.224,0.669,0.498,0.806l4.671,2.335c0.12,0.06,0.234,0.088,0.337,0.088 c0.29,0,0.494-0.225,0.494-0.602V7.231C9,7.208,8.988,7.188,8.968,7.178z\"><\/path><\/svg><span class=\"wp-block-social-link-label screen-reader-text\">Medium<\/span><\/a><\/li><\/ul>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Nowadays, it is very common to run applications on Spot instances. In this scenario, where a spot instance could be terminated at any point of time because of AWS pulling back their resource or ASG Scale-In incident, we need to have something in place to handle the termination smoothly so that we can complete our &hellip; <a href=\"https:\/\/opstree.com\/blog\/2022\/02\/08\/learn-the-hacks-for-running-custom-scripts-at-spot-termination\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Learn the Hacks for Running Custom Scripts at Spot Termination&#8221;<\/span><\/a><\/p>\n","protected":false},"author":216838376,"featured_media":29900,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_coblocks_attr":"","_coblocks_dimensions":"","_coblocks_responsive_height":"","_coblocks_accordion_ie_support":"","jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false},"version":2}},"categories":[28070474],"tags":[768739294,460,69816,768739298,455,169185036,9599486,35354816,4996032,363408,412212922],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/opstree.com\/blog\/wp-content\/uploads\/2025\/11\/DevSecOps-1.jpg","jetpack_likes_enabled":true,"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/pfDBOm-2y2","jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/posts\/9798"}],"collection":[{"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/users\/216838376"}],"replies":[{"embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/comments?post=9798"}],"version-history":[{"count":24,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/posts\/9798\/revisions"}],"predecessor-version":[{"id":9962,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/posts\/9798\/revisions\/9962"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/media\/29900"}],"wp:attachment":[{"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/media?parent=9798"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/categories?post=9798"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/tags?post=9798"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}