{"componentChunkName":"component---src-templates-post-template-js","path":"/posts/raspberrypi-k3s-non-stop-release","result":{"data":{"markdownRemark":{"id":"9184f804-f186-5f79-b6fd-922a9c1f626c","html":"<p>最近 Raspberry Pi で遊び始め、Raspberry Pi 上で動いているプログラムを無停止で更新できたら面白いなと思い、k3s を使った無停止リリースに挑戦してみました。</p>\n<p>最終的には、プログラムの更新によって、以下のように途中で L チカのスピードが速くなります。</p>\n<center>\n  <video width=\"320\" height=\"240\" controls>\n    <source src=\"/media/raspberrypi-k3s-non-stop-release-demo.mp4\" type=\"video/mp4\">\n  </video>\n</center>\n<h2 id=\"環境\" style=\"position:relative;\"><a href=\"#%E7%92%B0%E5%A2%83\" aria-label=\"環境 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>環境</h2>\n<ul>\n<li><a href=\"https://amzn.to/3uxyMnk\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Raspberry Pi 4 Model B</a></li>\n<li>OS … Raspbian</li>\n</ul>\n<p><a href=\"https://www.amazon.co.jp/dp/B081YD3VL5/ref=as_li_ss_il?ie=UTF8&linkCode=li2&tag=oshimayuki0d-22&linkId=573cedd3f64001e4e474596b9d5c2e51\" target=\"_blank\"><img border=\"0\" src=\"//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&ASIN=B081YD3VL5&Format=_SL160_&ID=AsinImage&MarketPlace=JP&ServiceVersion=20070822&WS=1&tag=oshimayuki0d-22\" ></a><img src=\"https://ir-jp.amazon-adsystem.com/e/ir?t=oshimayuki0d-22&amp;l=li2&amp;o=9&amp;a=B081YD3VL5\" width=\"1\" height=\"1\" border=\"0\" alt=\"\" style=\"border:none !important; margin:0px !important;\"></p>\n<h2 id=\"方針\" style=\"position:relative;\"><a href=\"#%E6%96%B9%E9%87%9D\" aria-label=\"方針 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>方針</h2>\n<p>さて、まずはどうやって無停止でプログラムを更新するかを考えてみます。</p>\n<p>GPIO を複数のプログラムが同時にさわるとよくないことになりそうなので、GPIO を扱うプログラムを無停止で更新するのは少しハードルが高そうです。</p>\n<p>そこで、「GPIO を扱うプログラム」と「GPIO に与える値を計算するプログラム」を別プロセスにする方針を考えてみました。</p>\n<p>下図のようなイメージです。</p>\n<p><img src=\"/media/raspberrypi-k3s-non-stop-release-architecture.jpg\" alt=\"raspberrypi-k3s-non-stop-release-architecture.jpg\"></p>\n<p>この「GPIO を扱うプロセス」から「計算を担当するプロセス」に向けて定期的に HTTP リクエストを送り、その結果を GPIO に出力する流れです。</p>\n<p>その上で、サーバ側のプログラムの更新は k3s を使えば簡単に無停止でできそうなので、k3s を使ってみようと思います。</p>\n<h2 id=\"k3s-のセットアップ\" style=\"position:relative;\"><a href=\"#k3s-%E3%81%AE%E3%82%BB%E3%83%83%E3%83%88%E3%82%A2%E3%83%83%E3%83%97\" aria-label=\"k3s のセットアップ permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>k3s のセットアップ</h2>\n<p>もし k3s が動かないと方針から考え直しなので、最初に k3s をセットアップして動作確認します。</p>\n<p>といってもめちゃくちゃ簡単で、Raspberry Pi 上で以下のコマンドを実行するだけです。</p>\n<div class=\"gatsby-highlight\" data-language=\"console\"><pre class=\"language-console\"><code class=\"language-console\">curl -sfL https://get.k3s.io | sh -</code></pre></div>\n<p>この際、私の環境では cgroup の設定の関係でエラーになりましたが、エラーメッセージの通り対処して reboot すれば解決しました。</p>\n<p>参考: <a href=\"https://github.com/k3s-io/k3s/issues/2067\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">k3s on pi error - cgroup<em>memory=1 cgroup</em>enable=memory #2067</a></p>\n<p>ちなみに、もともとは MicroK8s を使おうと思っていたのですが、手こずりそうな雰囲気を感じたため k3s に変更しました。</p>\n<p>参考: <a href=\"https://github.com/ubuntu/microk8s/issues/719\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Microk8s on armhf architecture #719</a></p>\n<p>インストールしたら <code class=\"language-text\">kubectl run</code> や <code class=\"language-text\">kubectl get pod</code> などでコンテナを動かせることを確認しておきましょう。</p>\n<h2 id=\"通信のインタフェースを決める\" style=\"position:relative;\"><a href=\"#%E9%80%9A%E4%BF%A1%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%95%E3%82%A7%E3%83%BC%E3%82%B9%E3%82%92%E6%B1%BA%E3%82%81%E3%82%8B\" aria-label=\"通信のインタフェースを決める permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>通信のインタフェースを決める</h2>\n<p>実装に入る前に、クライアント側・サーバ側が HTTP で通信するときのインタフェースを決める必要があります。</p>\n<p>今回は L チカで済ませるつもりなので何でも良いのですが、今後複数の PIN を扱えるよう、以下のようにしました。</p>\n<div class=\"gatsby-highlight\" data-language=\"json\"><pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n  <span class=\"token property\">\"gpios\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n    <span class=\"token punctuation\">{</span>\n      <span class=\"token property\">\"pin\"</span><span class=\"token operator\">:</span> <span class=\"token number\">21</span><span class=\"token punctuation\">,</span>\n      <span class=\"token property\">\"value\"</span><span class=\"token operator\">:</span> <span class=\"token number\">1</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">]</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>value が 1 なら ON、0 なら OFF となります。</p>\n<h2 id=\"クライアント側のプログラム\" style=\"position:relative;\"><a href=\"#%E3%82%AF%E3%83%A9%E3%82%A4%E3%82%A2%E3%83%B3%E3%83%88%E5%81%B4%E3%81%AE%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0\" aria-label=\"クライアント側のプログラム permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>クライアント側のプログラム</h2>\n<p>では、GPIO を扱う、クライアント側に相当するプログラムを用意します。</p>\n<p>Python ならライブラリを入れたりせずに GPIO が扱えたので、Python で書いてみました。</p>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token keyword\">import</span> RPi<span class=\"token punctuation\">.</span>GPIO <span class=\"token keyword\">as</span> GPIO\n<span class=\"token keyword\">import</span> time\n<span class=\"token keyword\">import</span> datetime\n<span class=\"token keyword\">import</span> requests\n\nURL <span class=\"token operator\">=</span> <span class=\"token string\">'http://localhost:30000'</span>\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">request_gpios</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n  response <span class=\"token operator\">=</span> requests<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span>URL<span class=\"token punctuation\">,</span> timeout<span class=\"token operator\">=</span><span class=\"token punctuation\">(</span><span class=\"token number\">1</span><span class=\"token punctuation\">,</span> <span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n  body <span class=\"token operator\">=</span> response<span class=\"token punctuation\">.</span>json<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n  now <span class=\"token operator\">=</span> datetime<span class=\"token punctuation\">.</span>datetime<span class=\"token punctuation\">.</span>now<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">print</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">str</span><span class=\"token punctuation\">(</span>now<span class=\"token punctuation\">)</span> <span class=\"token operator\">+</span> <span class=\"token string\">' | body: '</span> <span class=\"token operator\">+</span> <span class=\"token builtin\">str</span><span class=\"token punctuation\">(</span>body<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">return</span> body<span class=\"token punctuation\">[</span><span class=\"token string\">'gpios'</span><span class=\"token punctuation\">]</span>\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">setup_gpios</span><span class=\"token punctuation\">(</span>gpios<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n  <span class=\"token keyword\">for</span> gpio <span class=\"token keyword\">in</span> gpios<span class=\"token punctuation\">:</span>\n    pin <span class=\"token operator\">=</span> gpio<span class=\"token punctuation\">[</span><span class=\"token string\">'pin'</span><span class=\"token punctuation\">]</span>\n    GPIO<span class=\"token punctuation\">.</span>setup<span class=\"token punctuation\">(</span>pin<span class=\"token punctuation\">,</span> GPIO<span class=\"token punctuation\">.</span>OUT<span class=\"token punctuation\">)</span>\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">output_gpios</span><span class=\"token punctuation\">(</span>gpios<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n  <span class=\"token keyword\">for</span> gpio <span class=\"token keyword\">in</span> gpios<span class=\"token punctuation\">:</span>\n    pin <span class=\"token operator\">=</span> gpio<span class=\"token punctuation\">[</span><span class=\"token string\">'pin'</span><span class=\"token punctuation\">]</span>\n    value <span class=\"token operator\">=</span> gpio<span class=\"token punctuation\">[</span><span class=\"token string\">'value'</span><span class=\"token punctuation\">]</span>\n    GPIO<span class=\"token punctuation\">.</span>output<span class=\"token punctuation\">(</span>pin<span class=\"token punctuation\">,</span> value<span class=\"token punctuation\">)</span>\n\nGPIO<span class=\"token punctuation\">.</span>setmode<span class=\"token punctuation\">(</span>GPIO<span class=\"token punctuation\">.</span>BCM<span class=\"token punctuation\">)</span>\n\n<span class=\"token keyword\">try</span><span class=\"token punctuation\">:</span>\n  gpios <span class=\"token operator\">=</span> request_gpios<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n  setup_gpios<span class=\"token punctuation\">(</span>gpios<span class=\"token punctuation\">)</span>\n\n  <span class=\"token keyword\">while</span> <span class=\"token boolean\">True</span><span class=\"token punctuation\">:</span>\n    gpios <span class=\"token operator\">=</span> request_gpios<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    output_gpios<span class=\"token punctuation\">(</span>gpios<span class=\"token punctuation\">)</span>\n    time<span class=\"token punctuation\">.</span>sleep<span class=\"token punctuation\">(</span><span class=\"token number\">0.5</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token keyword\">except</span> KeyboardInterrupt<span class=\"token punctuation\">:</span>\n  GPIO<span class=\"token punctuation\">.</span>cleanup<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>0.5 秒ごとにリクエストを送り、その結果を GPIO に出力しているだけです。</p>\n<p>サーバ側もできたら、以下のように実行することになります。</p>\n<div class=\"gatsby-highlight\" data-language=\"console\"><pre class=\"language-console\"><code class=\"language-console\">$ python main.py\n2021-05-08 19:57:36.481347 | body: {u&#39;gpios&#39;: [{u&#39;value&#39;: 1, u&#39;pin&#39;: 21}]}\n2021-05-08 19:57:36.491097 | body: {u&#39;gpios&#39;: [{u&#39;value&#39;: 1, u&#39;pin&#39;: 21}]}\n2021-05-08 19:57:36.998604 | body: {u&#39;gpios&#39;: [{u&#39;value&#39;: 0, u&#39;pin&#39;: 21}]}\n    :</code></pre></div>\n<h2 id=\"サーバ側のプログラム\" style=\"position:relative;\"><a href=\"#%E3%82%B5%E3%83%BC%E3%83%90%E5%81%B4%E3%81%AE%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0\" aria-label=\"サーバ側のプログラム permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>サーバ側のプログラム</h2>\n<p>次に、サーバ側のプログラムを作成します。</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> http <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"http\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">const</span> process <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"process\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token constant\">PORT</span> <span class=\"token operator\">=</span> <span class=\"token number\">3000</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">const</span> <span class=\"token constant\">INTERVAL_MILLIS</span> <span class=\"token operator\">=</span> process<span class=\"token punctuation\">.</span>env<span class=\"token punctuation\">.</span><span class=\"token constant\">INTERVAL_MILLIS</span> <span class=\"token operator\">||</span> <span class=\"token number\">1000</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token constant\">ON_RESPONSE</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n  gpios<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n    <span class=\"token punctuation\">{</span>\n      pin<span class=\"token operator\">:</span> <span class=\"token number\">21</span><span class=\"token punctuation\">,</span>\n      value<span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token constant\">OFF_RESPONSE</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n  gpios<span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n    <span class=\"token punctuation\">{</span>\n      pin<span class=\"token operator\">:</span> <span class=\"token number\">21</span><span class=\"token punctuation\">,</span>\n      value<span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">var</span> response <span class=\"token operator\">=</span> <span class=\"token constant\">ON_RESPONSE</span><span class=\"token punctuation\">;</span>\n\nintervalObj <span class=\"token operator\">=</span> <span class=\"token function\">setInterval</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  response <span class=\"token operator\">=</span> response <span class=\"token operator\">===</span> <span class=\"token constant\">ON_RESPONSE</span> <span class=\"token operator\">?</span> <span class=\"token constant\">OFF_RESPONSE</span> <span class=\"token operator\">:</span> <span class=\"token constant\">ON_RESPONSE</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token constant\">INTERVAL_MILLIS</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">const</span> server <span class=\"token operator\">=</span> http\n  <span class=\"token punctuation\">.</span><span class=\"token function\">createServer</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">req<span class=\"token punctuation\">,</span> res</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    res<span class=\"token punctuation\">.</span><span class=\"token function\">writeHead</span><span class=\"token punctuation\">(</span><span class=\"token number\">200</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> <span class=\"token string\">\"Content-Type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"text/plain\"</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">const</span> body <span class=\"token operator\">=</span> <span class=\"token constant\">JSON</span><span class=\"token punctuation\">.</span><span class=\"token function\">stringify</span><span class=\"token punctuation\">(</span>response<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n    res<span class=\"token punctuation\">.</span><span class=\"token function\">end</span><span class=\"token punctuation\">(</span>body<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">const</span> now <span class=\"token operator\">=</span> Date<span class=\"token punctuation\">.</span><span class=\"token function\">now</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>now <span class=\"token operator\">+</span> <span class=\"token string\">\" | body: \"</span> <span class=\"token operator\">+</span> body<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">.</span><span class=\"token function\">listen</span><span class=\"token punctuation\">(</span><span class=\"token constant\">PORT</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"Server http://localhost:\"</span> <span class=\"token operator\">+</span> <span class=\"token constant\">PORT</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\nprocess<span class=\"token punctuation\">.</span><span class=\"token function\">on</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"SIGTERM\"</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token comment\">// リクエストの処理中かもしれないので 5 秒待つ</span>\n  <span class=\"token function\">setTimeout</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"Received SIGTERM at \"</span> <span class=\"token operator\">+</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Date</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    server<span class=\"token punctuation\">.</span><span class=\"token function\">close</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"Server closed\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token function\">clearInterval</span><span class=\"token punctuation\">(</span>intervalObj<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"intervalObj cleared\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token number\">5000</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>クライアント側と比べると少し長いですが、ざっくり言えば、環境変数 INTERVAL_MILLIS で指定した時間ごとにレスポンスの ON/OFF の値が切り替わるだけです。</p>\n<p>コードの最後の部分については、k3s でコンテナを更新する際に古いほうのコンテナに飛ぶ SIGTERM をうまくハンドリング (Graceful Shutdown) するための記述です。</p>\n<p>試しに実行して <code class=\"language-text\">curl localhost:3000</code> のようなリクエストを送ると、以下のようになります。</p>\n<div class=\"gatsby-highlight\" data-language=\"console\"><pre class=\"language-console\"><code class=\"language-console\">$ node server.js\nServer http://localhost:3000\n1620471867537 | body: {&quot;gpios&quot;:[{&quot;pin&quot;:21,&quot;value&quot;:1}]}\n1620471868278 | body: {&quot;gpios&quot;:[{&quot;pin&quot;:21,&quot;value&quot;:1}]}\n1620471868861 | body: {&quot;gpios&quot;:[{&quot;pin&quot;:21,&quot;value&quot;:0}]}\n    :</code></pre></div>\n<h2 id=\"サーバ側のコンテナイメージを作成\" style=\"position:relative;\"><a href=\"#%E3%82%B5%E3%83%BC%E3%83%90%E5%81%B4%E3%81%AE%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E3%82%A4%E3%83%A1%E3%83%BC%E3%82%B8%E3%82%92%E4%BD%9C%E6%88%90\" aria-label=\"サーバ側のコンテナイメージを作成 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>サーバ側のコンテナイメージを作成</h2>\n<p>クライアント側、サーバ側のプログラムができたので、サーバ側をコンテナにしようと思います。</p>\n<p>コンテナ化したいので、Dockerfile を書きます</p>\n<div class=\"gatsby-highlight\" data-language=\"dockerfile\"><pre class=\"language-dockerfile\"><code class=\"language-dockerfile\"><span class=\"token keyword\">FROM</span> node<span class=\"token punctuation\">:</span>14.16.1<span class=\"token punctuation\">-</span>alpine\n\n<span class=\"token keyword\">COPY</span> server.js /opt/app/\n\n<span class=\"token keyword\">ENTRYPOINT</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"node\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"/opt/app/server.js\"</span><span class=\"token punctuation\">]</span></code></pre></div>\n<p>docker build して、Docker Hub に push します。</p>\n<div class=\"gatsby-highlight\" data-language=\"console\"><pre class=\"language-console\"><code class=\"language-console\">$ docker build -t &lt;イメージ名&gt; .\n$ docker login\n$ docker push &lt;イメージ名&gt;</code></pre></div>\n<h2 id=\"k3s-へのデプロイ\" style=\"position:relative;\"><a href=\"#k3s-%E3%81%B8%E3%81%AE%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4\" aria-label=\"k3s へのデプロイ permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>k3s へのデプロイ</h2>\n<p>k3s にデプロイするため、マニフェストファイルを作成します。</p>\n<div class=\"gatsby-highlight\" data-language=\"yaml\"><pre class=\"language-yaml\"><code class=\"language-yaml\"><span class=\"token key atrule\">apiVersion</span><span class=\"token punctuation\">:</span> v1\n<span class=\"token key atrule\">kind</span><span class=\"token punctuation\">:</span> Service\n<span class=\"token key atrule\">metadata</span><span class=\"token punctuation\">:</span>\n  <span class=\"token key atrule\">labels</span><span class=\"token punctuation\">:</span>\n    <span class=\"token key atrule\">app</span><span class=\"token punctuation\">:</span> app\n  <span class=\"token key atrule\">name</span><span class=\"token punctuation\">:</span> app\n<span class=\"token key atrule\">spec</span><span class=\"token punctuation\">:</span>\n  <span class=\"token key atrule\">type</span><span class=\"token punctuation\">:</span> NodePort\n  <span class=\"token key atrule\">selector</span><span class=\"token punctuation\">:</span>\n    <span class=\"token key atrule\">app</span><span class=\"token punctuation\">:</span> app\n  <span class=\"token key atrule\">ports</span><span class=\"token punctuation\">:</span>\n  <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">port</span><span class=\"token punctuation\">:</span> <span class=\"token number\">3000</span>\n    <span class=\"token key atrule\">targetPort</span><span class=\"token punctuation\">:</span> <span class=\"token number\">3000</span>\n    <span class=\"token key atrule\">nodePort</span><span class=\"token punctuation\">:</span> <span class=\"token number\">30000</span>\n<span class=\"token punctuation\">---</span>\n<span class=\"token key atrule\">apiVersion</span><span class=\"token punctuation\">:</span> apps/v1\n<span class=\"token key atrule\">kind</span><span class=\"token punctuation\">:</span> Deployment\n<span class=\"token key atrule\">metadata</span><span class=\"token punctuation\">:</span>\n  <span class=\"token key atrule\">labels</span><span class=\"token punctuation\">:</span>\n    <span class=\"token key atrule\">app</span><span class=\"token punctuation\">:</span> app\n  <span class=\"token key atrule\">name</span><span class=\"token punctuation\">:</span> app\n<span class=\"token key atrule\">spec</span><span class=\"token punctuation\">:</span>\n  <span class=\"token key atrule\">replicas</span><span class=\"token punctuation\">:</span> <span class=\"token number\">1</span>\n  <span class=\"token key atrule\">selector</span><span class=\"token punctuation\">:</span>\n    <span class=\"token key atrule\">matchLabels</span><span class=\"token punctuation\">:</span>\n      <span class=\"token key atrule\">app</span><span class=\"token punctuation\">:</span> app\n  <span class=\"token key atrule\">strategy</span><span class=\"token punctuation\">:</span>\n    <span class=\"token key atrule\">rollingUpdate</span><span class=\"token punctuation\">:</span>\n      <span class=\"token key atrule\">maxSurge</span><span class=\"token punctuation\">:</span> 50%\n      <span class=\"token key atrule\">maxUnavailable</span><span class=\"token punctuation\">:</span> 50%\n  <span class=\"token key atrule\">template</span><span class=\"token punctuation\">:</span>\n    <span class=\"token key atrule\">metadata</span><span class=\"token punctuation\">:</span>\n      <span class=\"token key atrule\">labels</span><span class=\"token punctuation\">:</span>\n        <span class=\"token key atrule\">app</span><span class=\"token punctuation\">:</span> app\n    <span class=\"token key atrule\">spec</span><span class=\"token punctuation\">:</span>\n      <span class=\"token key atrule\">containers</span><span class=\"token punctuation\">:</span>\n      <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">name</span><span class=\"token punctuation\">:</span> app\n        <span class=\"token key atrule\">image</span><span class=\"token punctuation\">:</span> &lt;イメージ名<span class=\"token punctuation\">></span>\n        <span class=\"token key atrule\">ports</span><span class=\"token punctuation\">:</span>\n        <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">containerPort</span><span class=\"token punctuation\">:</span> <span class=\"token number\">3000</span>\n        <span class=\"token key atrule\">livenessProbe</span><span class=\"token punctuation\">:</span>\n          <span class=\"token key atrule\">failureThreshold</span><span class=\"token punctuation\">:</span> <span class=\"token number\">3</span>\n          <span class=\"token key atrule\">httpGet</span><span class=\"token punctuation\">:</span>\n            <span class=\"token key atrule\">path</span><span class=\"token punctuation\">:</span> /\n            <span class=\"token key atrule\">port</span><span class=\"token punctuation\">:</span> <span class=\"token number\">3000</span>\n          <span class=\"token key atrule\">periodSeconds</span><span class=\"token punctuation\">:</span> <span class=\"token number\">60</span>\n          <span class=\"token key atrule\">timeoutSeconds</span><span class=\"token punctuation\">:</span> <span class=\"token number\">3</span>\n        <span class=\"token key atrule\">readinessProbe</span><span class=\"token punctuation\">:</span>\n          <span class=\"token key atrule\">failureThreshold</span><span class=\"token punctuation\">:</span> <span class=\"token number\">3</span>\n          <span class=\"token key atrule\">httpGet</span><span class=\"token punctuation\">:</span>\n            <span class=\"token key atrule\">path</span><span class=\"token punctuation\">:</span> /\n            <span class=\"token key atrule\">port</span><span class=\"token punctuation\">:</span> <span class=\"token number\">3000</span>\n          <span class=\"token key atrule\">periodSeconds</span><span class=\"token punctuation\">:</span> <span class=\"token number\">5</span>\n          <span class=\"token key atrule\">timeoutSeconds</span><span class=\"token punctuation\">:</span> <span class=\"token number\">3</span>\n        <span class=\"token key atrule\">resources</span><span class=\"token punctuation\">:</span>\n          <span class=\"token key atrule\">limits</span><span class=\"token punctuation\">:</span>\n            <span class=\"token key atrule\">cpu</span><span class=\"token punctuation\">:</span> 500m\n            <span class=\"token key atrule\">memory</span><span class=\"token punctuation\">:</span> 250Mi\n          <span class=\"token key atrule\">requests</span><span class=\"token punctuation\">:</span>\n            <span class=\"token key atrule\">cpu</span><span class=\"token punctuation\">:</span> 500m\n            <span class=\"token key atrule\">memory</span><span class=\"token punctuation\">:</span> 250Mi\n        <span class=\"token key atrule\">env</span><span class=\"token punctuation\">:</span>\n        <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">name</span><span class=\"token punctuation\">:</span> INTERVAL_MILLIS\n          <span class=\"token key atrule\">value</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"2000\"</span>\n      <span class=\"token key atrule\">restartPolicy</span><span class=\"token punctuation\">:</span> Always\n      <span class=\"token key atrule\">terminationGracePeriodSeconds</span><span class=\"token punctuation\">:</span> <span class=\"token number\">60</span></code></pre></div>\n<p>これを適用してしばらく待てば、コンテナが起動しています。</p>\n<div class=\"gatsby-highlight\" data-language=\"console\"><pre class=\"language-console\"><code class=\"language-console\">$ kubectl apply -f app.yaml\nservice/app created\ndeployment.apps/app created\n$ kubectl get po\nNAME                   READY   STATUS    RESTARTS   AGE\napp-7878c59946-4wfkk   1/1     Running   0          95m</code></pre></div>\n<p>※ 実際にはプライベートなレジストリを使ったので、その設定もしています。</p>\n<p>参考: <a href=\"https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Pull an Image from a Private Registry</a></p>\n<p>クライアント側を Raspberry Pi 上で実行すると、無事疎通します！このとき、LED もチカチカします！</p>\n<div class=\"gatsby-highlight\" data-language=\"console\"><pre class=\"language-console\"><code class=\"language-console\">$ python main.py\n2021-05-08 20:19:55.393659 | body: {u&#39;gpios&#39;: [{u&#39;value&#39;: 1, u&#39;pin&#39;: 21}]}\n2021-05-08 20:19:55.400793 | body: {u&#39;gpios&#39;: [{u&#39;value&#39;: 1, u&#39;pin&#39;: 21}]}\n2021-05-08 20:19:55.908066 | body: {u&#39;gpios&#39;: [{u&#39;value&#39;: 0, u&#39;pin&#39;: 21}]}\n    :</code></pre></div>\n<h2 id=\"無停止で更新してみる\" style=\"position:relative;\"><a href=\"#%E7%84%A1%E5%81%9C%E6%AD%A2%E3%81%A7%E6%9B%B4%E6%96%B0%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B\" aria-label=\"無停止で更新してみる permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>無停止で更新してみる</h2>\n<p>では最後に、無停止で更新できるか試します。</p>\n<p>本当ならプログラムを書き換えて反映したいのですが、少し手間がかかります。</p>\n<p>Deployment の環境変数を変えるだけでも同じ挙動になるので、環境変数の変更で試してみます。</p>\n<p>簡易的に <code class=\"language-text\">kubectl edit deploy app</code> で INTERVAL_MILLIS を 500 に変更すると…</p>\n<center>\n  <video width=\"320\" height=\"240\" controls>\n    <source src=\"/media/raspberrypi-k3s-non-stop-release-demo.mp4\" type=\"video/mp4\">\n  </video>\n</center>\n<p>無事、無停止で挙動が切り替わりました！</p>\n<h2 id=\"考察\" style=\"position:relative;\"><a href=\"#%E8%80%83%E5%AF%9F\" aria-label=\"考察 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>考察</h2>\n<p>一応やりたかったことは達成しましたが、この方針でよかったのか少し考えてみようと思います。</p>\n<p>今回は「GPIO を扱うプログラム」と「GPIO に与える値を計算するプログラム」を別プロセスにする方針にすることと、k3s を使ったローリングアップデートで、無停止での動作の切り替えを実現しました。</p>\n<p>Kubernetes の使い方さえ知っていれば簡単だったので、基本的には悪くない方針だったと思います。</p>\n<h3 id=\"今回の方針の欠点\" style=\"position:relative;\"><a href=\"#%E4%BB%8A%E5%9B%9E%E3%81%AE%E6%96%B9%E9%87%9D%E3%81%AE%E6%AC%A0%E7%82%B9\" aria-label=\"今回の方針の欠点 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>今回の方針の欠点</h3>\n<p>ただ、大きな欠点として、「GPIO を扱うプログラム」側は無停止で更新できないことが挙げられます。</p>\n<p>「GPIO を扱うプログラム」の更新がある際は無停止リリースしている場合じゃない気もするので、これでもいいかもしれませんが、改善する方法も考えておきたいです。</p>\n<p>例えば、「GPIO を扱うプロセス」を「リクエストに応じて GPIO を処理するプロセス」と「定期的にリクエストを送るプロセス」に分離し、無停止で更新できないのは「定期的にリクエストを送る」という薄いプログラムだけにするといった方針が考えられます。</p>\n<p>他には、「GPIO を扱うプログラム」の新版・旧版を並列稼働させ、特定時刻になったら切り替わるようにする処理を入れる、といった方法でも実現できるかもしれません。</p>\n<p>後者の方法はうまく動作するのか検証するのがかなり大変な気がするので、本当にそこまでするのか要検討だと思います。</p>\n<h2 id=\"おわりに\" style=\"position:relative;\"><a href=\"#%E3%81%8A%E3%82%8F%E3%82%8A%E3%81%AB\" aria-label=\"おわりに permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>おわりに</h2>\n<p>ということで、「Raspberry Pi で L チカしてるプログラムを、k3s を使って無停止で更新する」という記事については以上になります。</p>\n<p>説明はスラスラ進んだように書きましたが、実際にはサーバ側のプログラムを Graceful Shutdown させる箇所などで少し手間取ったりしました。</p>\n<p>とはいえ、想像していたくらいの時間で一通りできたので、個人的には満足しています。</p>\n<p>今後の改良としては、まずは「GPIO を扱うプログラム」の方もコンテナ化してみることが考えられます。</p>\n<p>k3s 上のコンテナから GPIO を操作する例はいくつかあったので、たぶんできると思います。</p>\n<p>参考</p>\n<ul>\n<li><a href=\"https://qiita.com/sat0ken/items/8f68c092c8a0c4597c65\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">raspberry pi に k3s を入れてLチカアプリをデプロイしてみる</a></li>\n<li><a href=\"https://tech.virtualtech.jp/entry/2019/10/04/152802\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">コンテナーでLチカしてみる</a></li>\n</ul>\n<p>あとは、せっかく k3s を導入していろんなコンテナを連携させたりしやすくなったので、Tensorflow Serving や TorchServe のコンテナと連携させて、機械学習の結果を Raspberry Pi の挙動に反映したりしたら面白いかもしれません。</p>","fields":{"slug":"/posts/raspberrypi-k3s-non-stop-release","tagSlugs":["/tag/raspberrypi/","/tag/k-8-s/","/tag/iot/"],"autoRecommendPosts":["getting-started-with-aws-app-runner","raspberrypi-motordriver","raspberrypi-clean-architecture","aws-app-runner-with-cloud-native-buildpacks"]},"frontmatter":{"date":"2021-05-08T12:04:52.347Z","description":"最近 Raspberry Pi で遊び始め、Raspberry Pi 上で動いているプログラムを無停止で更新できたら面白いなと思い、k3s を使った無停止リリースに挑戦してみました。","tags":["raspberrypi","k8s","iot"],"title":"Raspberry Pi で L チカしてるプログラムを、k3s を使って無停止で更新する","socialImage":null,"recommendPosts":["https://www.kanzennirikaisita.com/posts/software-developer-books-index"]}}},"pageContext":{"slug":"/posts/raspberrypi-k3s-non-stop-release"}},"staticQueryHashes":["251939775","3942705351","401334301"]}