<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Infra on Yossy's Notes</title><link>https://yoshihiroshu.com/categories/infra/</link><description>Recent content in Infra on Yossy's Notes</description><generator>Hugo</generator><language>ja</language><lastBuildDate>Sun, 12 May 2024 12:00:00 +0900</lastBuildDate><atom:link href="https://yoshihiroshu.com/categories/infra/index.xml" rel="self" type="application/rss+xml"/><item><title>DBインスタンスを最大6台から2台に削減した話</title><link>https://yoshihiroshu.com/blog/db-instance-reduction/</link><pubDate>Sun, 12 May 2024 12:00:00 +0900</pubDate><guid>https://yoshihiroshu.com/blog/db-instance-reduction/</guid><description>&lt;div>&lt;a id="td-block-0" class="td-offset-anchor">&lt;/a>&lt;/div>
&lt;section class="row td-box td-box--white td-box--height-auto">
&lt;div class="col">
&lt;div class="container">
&lt;h2 id="自己紹介">自己紹介&lt;a class="td-heading-self-link" href="#%e8%87%aa%e5%b7%b1%e7%b4%b9%e4%bb%8b" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;p>私は、現在とあるWeb系のベンチャーでWebアプリケーションエンジニアとして開発業務に従事しています。&lt;/p>
&lt;p>今回の記事では以前勤務していた株式会社ZUUでの開発に関して投稿したいと思います。&lt;/p>
&lt;p>今回は肥大化したDBにインデックスを付与することで、DBインスタンス数を最大6台から2台までに改善することができたので説明していきたいと思います。&lt;/p>
&lt;p>&lt;strong>本記事は個人の見解です。&lt;/strong>&lt;/p>
&lt;h2 id="サービスについて">サービスについて&lt;a class="td-heading-self-link" href="#%e3%82%b5%e3%83%bc%e3%83%93%e3%82%b9%e3%81%ab%e3%81%a4%e3%81%84%e3%81%a6" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;p>株式会社ZUUでは金融に関する記事を掲載する様々なメディアを運営しています。&lt;/p>
&lt;p>ZUU Onlineやfuelle、MoneyTimes、dメニューマネー、その他にも多数メディアを運営しております。&lt;/p>
&lt;p>一部メディアでは、ユーザー機能を提供しており、その中にお気に入りの記事をクリップする機能などがあります。&lt;/p>
&lt;h2 id="概要">概要&lt;a class="td-heading-self-link" href="#%e6%a6%82%e8%a6%81" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;p>弊社の顔でもZUU onlineは、ローンチして約○年経ち、記事数やユーザー数ともに大きく成長しました。ただその一方でパフォーマンスの劣化などが問題となりユーザビリティを下げてしまうことに課題がありました。&lt;/p>
&lt;h2 id="前提">前提&lt;a class="td-heading-self-link" href="#%e5%89%8d%e6%8f%90" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;p>使用しているDBMSはPostgreSQL12です。&lt;/p>
&lt;p>今回改善したクエリを簡単な図で説明します。&lt;/p>
&lt;p>運用しているメディアでは、ユーザーが記事をクリップする機能が提供されています。&lt;/p>
&lt;p>その一部であるユーザーごとにクリップを取得する機能がボトルネックとなっていました。&lt;/p>
&lt;p>（以下のテーブルは例です。実際のテーブルとは異なります。）&lt;/p>
&lt;pre class="mermaid">erDiagram
 articles {
 id integer pk
 title text
 content text
 }
 article_clips{
 article_id integer fk
 user_id integer fk
 }
 users{
 id integer pk
 name text
 }
 articles ||--o{ article_clips : article_id
 users ||--o{ article_clips : user_id&lt;/pre>
&lt;p>それぞれおおよそ以下のレコード数を持っています。&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>テーブル名&lt;/th>
 &lt;th>レコード数&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>articles&lt;/td>
 &lt;td>120,000&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>article_clips&lt;/td>
 &lt;td>2,800,000&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>users&lt;/td>
 &lt;td>200,000&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="スロークエリの分析">スロークエリの分析&lt;a class="td-heading-self-link" href="#%e3%82%b9%e3%83%ad%e3%83%bc%e3%82%af%e3%82%a8%e3%83%aa%e3%81%ae%e5%88%86%e6%9e%90" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;p>スロークエリが判明したので、実行計画をもとに分析していきます。&lt;/p></description></item><item><title>Redisの負荷を1/3改善した話</title><link>https://yoshihiroshu.com/blog/redis-load-reduction/</link><pubDate>Sat, 16 Dec 2023 12:00:00 +0900</pubDate><guid>https://yoshihiroshu.com/blog/redis-load-reduction/</guid><description>&lt;div>&lt;a id="td-block-0" class="td-offset-anchor">&lt;/a>&lt;/div>
&lt;section class="row td-box td-box--white td-box--height-auto">
&lt;div class="col">
&lt;div class="container">
&lt;h2 id="はじめに">はじめに&lt;a class="td-heading-self-link" href="#%e3%81%af%e3%81%98%e3%82%81%e3%81%ab" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;p>現在とある金融系Webメディアを運営する会社で、主にバックエンドの開発を担当しており、フロントエンド、インフラに関する業務も担当しています。&lt;/p>
&lt;p>今回は、先輩エンジニアがデータ圧縮アルゴリズムを変更することでRedisの負荷を1/3に削減することに成功した実例をもとに記述して行きます。&lt;/p>
&lt;ul>
&lt;li>先輩エンジニア(通称 &lt;a href="https://github.com/ichigozero">ichigozero&lt;/a>)は、vimmer, hacker, rustが得意なエンジニアです。（共通の趣味（おうちKubernetes）について語り合うのが日課です。笑）&lt;/li>
&lt;/ul>
&lt;h2 id="サービスの概要">サービスの概要&lt;a class="td-heading-self-link" href="#%e3%82%b5%e3%83%bc%e3%83%93%e3%82%b9%e3%81%ae%e6%a6%82%e8%a6%81" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;p>金融に関する記事を掲載するWebメディアを運用しています。&lt;/p>
&lt;h2 id="背景">背景&lt;a class="td-heading-self-link" href="#%e8%83%8c%e6%99%af" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;p>現在運用しているメディアでは約100万記事掲載しており、直近一年で約50万記事と急激に増加し、Redisのパフォーマンスが劣化する課題がありました。&lt;/p>
&lt;p>RedisのCPU使用率が高負荷状態になると、インスタンスを増やすことで一時的な対応を行っていました。&lt;/p>
&lt;p>そこで根本的なアプローチをし、改善を行うとなったのが背景です。&lt;/p>
&lt;p>*別アプローチも行っており、大幅な改善が見られました。別記事にて紹介する予定です。&lt;/p>
&lt;h2 id="前提">前提&lt;a class="td-heading-self-link" href="#%e5%89%8d%e6%8f%90" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;h3 id="データ取得のフロー">データ取得のフロー&lt;a class="td-heading-self-link" href="#%e3%83%87%e3%83%bc%e3%82%bf%e5%8f%96%e5%be%97%e3%81%ae%e3%83%95%e3%83%ad%e3%83%bc" aria-label="Heading self-link">&lt;/a>&lt;/h3>&lt;p>サーバーでは、Redis-&amp;gt;PostgreSQLという順番で問い合わせを行っています。&lt;/p>
&lt;pre class="mermaid">sequenceDiagram
 participant Client
 participant Server
 participant Redis
 participant PostgreSQL

 Client-&amp;gt;Server: リクエスト

 Server-&amp;gt;Redis: Redisからデータを取得
 Redis-&amp;gt;Server: データが存在する場合、データを返す

 alt Redisからデータが存在しない場合
 Server-&amp;gt;PostgreSQL: PostgreSQLからデータを取得
 Server-&amp;gt;Redis: データを保存
 end

 Server-&amp;gt;Client: レスポンス&lt;/pre>
&lt;h2 id="解決策">解決策&lt;a class="td-heading-self-link" href="#%e8%a7%a3%e6%b1%ba%e7%ad%96" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;p>データ圧縮アルゴリズムのGob形式から、パフォーマンスの高いアルゴリズムであるMgspack形式とSnappy形式を採用することで、大幅な改善に成功しました。&lt;/p>
&lt;h3 id="採用理由">採用理由&lt;a class="td-heading-self-link" href="#%e6%8e%a1%e7%94%a8%e7%90%86%e7%94%b1" aria-label="Heading self-link">&lt;/a>&lt;/h3>&lt;p>データ圧縮のベンチマークについては、&lt;code>Gob&lt;/code>と&lt;code>Mgspack + Snappy&lt;/code>は同等のパフォーマンスです。&lt;/p>
&lt;p>しかしバイトサイズを比較すると&lt;code>Mgspack + Snappy&lt;/code>が&lt;code>Gob&lt;/code>と比べ、半分のサイズに圧縮することができています。&lt;/p>
&lt;p>結果、Redisのベンチマークを比べるとns/op(1回の操作にかかる平均時間)が約11%、B/op(1回の操作で消費する平均メモリ量)が約3%、allocs/op(1回の操作で生成される平均割り当て数)が約80%と大幅に改善したので採用しました。&lt;/p>
&lt;h3 id="ベンチマーク">ベンチマーク&lt;a class="td-heading-self-link" href="#%e3%83%99%e3%83%b3%e3%83%81%e3%83%9e%e3%83%bc%e3%82%af" aria-label="Heading self-link">&lt;/a>&lt;/h3>&lt;p>データ圧縮のベンチマーク&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-zsh" data-lang="zsh">&lt;span class="line">&lt;span class="cl">BenchmarkJSONMarshal-12 	 45304	 &lt;span class="m">25614&lt;/span> ns/op	 &lt;span class="m">17984&lt;/span> B/op	 &lt;span class="m">35&lt;/span> allocs/op
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">BenchmarkJSONUnmarshal-12 	 14763	 &lt;span class="m">81072&lt;/span> ns/op	 &lt;span class="m">31334&lt;/span> B/op	 &lt;span class="m">74&lt;/span> allocs/op
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">BenchmarkGobMarshal-12 	 120536	 &lt;span class="m">10011&lt;/span> ns/op	 &lt;span class="m">29876&lt;/span> B/op	 &lt;span class="m">51&lt;/span> allocs/op
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">BenchmarkGobUnmarshal-12 	 56109	 &lt;span class="m">21446&lt;/span> ns/op	 &lt;span class="m">36464&lt;/span> B/op	 &lt;span class="m">243&lt;/span> allocs/op
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">BenchmarkMsgpackMarshal-12 	 373802	 &lt;span class="m">2888&lt;/span> ns/op	 &lt;span class="m">28005&lt;/span> B/op	 &lt;span class="m">5&lt;/span> allocs/op
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">BenchmarkMsgpackUnmarshal-12 	 369746	 &lt;span class="m">3261&lt;/span> ns/op	 &lt;span class="m">15286&lt;/span> B/op	 &lt;span class="m">34&lt;/span> allocs/op
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">BenchmarkMsgpackSnappyMarshal-12 	 55236	 &lt;span class="m">21330&lt;/span> ns/op	 &lt;span class="m">44386&lt;/span> B/op	 &lt;span class="m">5&lt;/span> allocs/op
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">BenchmarkMsgpackSnappyUnmarshal-12 	 140824	 &lt;span class="m">8507&lt;/span> ns/op	 &lt;span class="m">28951&lt;/span> B/op	 &lt;span class="m">35&lt;/span> allocs/op
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Redisベンチマーク&lt;/p></description></item><item><title>これだけは知っておきたいDNS</title><link>https://yoshihiroshu.com/blog/dns-basic-knowledge/</link><pubDate>Sun, 30 Jul 2023 12:00:00 +0900</pubDate><guid>https://yoshihiroshu.com/blog/dns-basic-knowledge/</guid><description>&lt;div>&lt;a id="td-block-0" class="td-offset-anchor">&lt;/a>&lt;/div>
&lt;section class="row td-box td-box--white td-box--height-auto">
&lt;div class="col">
&lt;div class="container">
&lt;h2 id="はじめに">はじめに&lt;a class="td-heading-self-link" href="#%e3%81%af%e3%81%98%e3%82%81%e3%81%ab" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;p>DNSについて、最低限知っておきたいポイントを整理しました。誰かのお役に立てれば幸いです。&lt;/p>
&lt;h2 id="登場人物">登場人物&lt;a class="td-heading-self-link" href="#%e7%99%bb%e5%a0%b4%e4%ba%ba%e7%89%a9" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;h2 id="dnsを動かすために必要なこと">DNSを動かすために必要なこと&lt;a class="td-heading-self-link" href="#dns%e3%82%92%e5%8b%95%e3%81%8b%e3%81%99%e3%81%9f%e3%82%81%e3%81%ab%e5%bf%85%e8%a6%81%e3%81%aa%e3%81%93%e3%81%a8" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;ul>
&lt;li>自分のドメイン名をインターネットでつけるようにする
　- 権威サーバーを動かすことで自分のドメイン名をインターネットで使えるようにする&lt;/li>
&lt;li>インターネットで使われているドメイン名を自分が使えるようにする
&lt;ul>
&lt;li>フルリゾルバー、スタブリゾルバー、特にフルリゾルバーを動かすことでインターネットで使われているドメインを自分で使えるようにする&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>DNSを動かし続け、可用性を高める
&lt;ul>
&lt;li>問題なく動作していることを確認すること、外部攻撃に備え動かし続ける必要がある&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="dns設計">DNS設計&lt;a class="td-heading-self-link" href="#dns%e8%a8%ad%e8%a8%88" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;h3 id="ユースケース">ユースケース&lt;a class="td-heading-self-link" href="#%e3%83%a6%e3%83%bc%e3%82%b9%e3%82%b1%e3%83%bc%e3%82%b9" aria-label="Heading self-link">&lt;/a>&lt;/h3>&lt;ul>
&lt;li>
&lt;p>運用しているサービスやサーバーが少ない場合
サブドメインを作成せず、階層構造を持たないフラットな管理をする。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>部門別のシステムをサブドメインを作成し、システム部門が全体の管理する場合
1つのゾーンで運用する&lt;/p>
&lt;/li>
&lt;li>
&lt;p>他部門が独自サブドメインを使ってサービスサイトを運用し、そのサブドメインもその部門が管理する場合
サブドメインを作成し、ゾーンの管理をその部門委任する&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h2 id="権威サーバーの可用性">権威サーバーの可用性&lt;a class="td-heading-self-link" href="#%e6%a8%a9%e5%a8%81%e3%82%b5%e3%83%bc%e3%83%90%e3%83%bc%e3%81%ae%e5%8f%af%e7%94%a8%e6%80%a7" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;h3 id="プライマリサーバーとセカンダリサーバーの設置">プライマリサーバーとセカンダリサーバーの設置&lt;a class="td-heading-self-link" href="#%e3%83%97%e3%83%a9%e3%82%a4%e3%83%9e%e3%83%aa%e3%82%b5%e3%83%bc%e3%83%90%e3%83%bc%e3%81%a8%e3%82%bb%e3%82%ab%e3%83%b3%e3%83%80%e3%83%aa%e3%82%b5%e3%83%bc%e3%83%90%e3%83%bc%e3%81%ae%e8%a8%ad%e7%bd%ae" aria-label="Heading self-link">&lt;/a>&lt;/h3>&lt;p>&lt;strong>役割&lt;/strong>
プライマリサーバーがセカンダリサーバーからのゾーン転送の要求を受け、要求されたゾーンデータを送る&lt;/p>
&lt;p>&lt;strong>考慮すること&lt;/strong>&lt;/p>
&lt;p>プライマリサーバーをセカンダリサーバーへのゾーン転送のコピー元としてだけ使う。&lt;/p>
&lt;ul>
&lt;li>利用者からの問い合わせは受け付けないように構成する
プライマリサーバーのIPアドレスをプライベートにすることで、サイバー攻撃のリスクを減らすことができる&lt;/li>
&lt;/ul>
&lt;h3 id="ゾーン転送の仕組み">ゾーン転送の仕組み&lt;a class="td-heading-self-link" href="#%e3%82%be%e3%83%bc%e3%83%b3%e8%bb%a2%e9%80%81%e3%81%ae%e4%bb%95%e7%b5%84%e3%81%bf" aria-label="Heading self-link">&lt;/a>&lt;/h3>&lt;ul>
&lt;li>AXFR
全てのゾーン情報を転送する&lt;/li>
&lt;li>IXFR
前回のゾーン転送情報をジャーナルファイルに記録しておき、ゾーン転送時にはジャーナルファイルを参照して差分情報のみを転送する&lt;/li>
&lt;/ul>
&lt;h2 id="権威サーバーが応答する情報">権威サーバーが応答する情報&lt;a class="td-heading-self-link" href="#%e6%a8%a9%e5%a8%81%e3%82%b5%e3%83%bc%e3%83%90%e3%83%bc%e3%81%8c%e5%bf%9c%e7%ad%94%e3%81%99%e3%82%8b%e6%83%85%e5%a0%b1" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;ul>
&lt;li>リソースレコードの表記フォーマット
&lt;ul>
&lt;li>TTLとクラスは省略できる&lt;/li>
&lt;li>同じドメイン名に複数のリソースレコードを設定する場合、二行目以降はドメイン名を省略できる&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-jsx" data-lang="jsx">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">TTL&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">class&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">type&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> &lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">data&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="フルリゾルバー">フルリゾルバー&lt;a class="td-heading-self-link" href="#%e3%83%95%e3%83%ab%e3%83%aa%e3%82%be%e3%83%ab%e3%83%90%e3%83%bc" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;p>&lt;strong>役割&lt;/strong>&lt;/p>
&lt;p>利用者の機器で動作するスタブリゾルバーから名前解決要求を受け付け、名前解決を行い結果を返す&lt;/p>
&lt;p>&lt;strong>考慮すること&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>ネット上に設置された権威サーバー群に問い合わせを送るため、一般的にグローバルIPを割り当てる&lt;/li>
&lt;li>利用者のネットワークからアクセスしやすい場所に設置することが望ましい&lt;/li>
&lt;/ul>
&lt;h2 id="代表的に攻撃手法">代表的に攻撃手法&lt;a class="td-heading-self-link" href="#%e4%bb%a3%e8%a1%a8%e7%9a%84%e3%81%ab%e6%94%bb%e6%92%83%e6%89%8b%e6%b3%95" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;h3 id="dnsリフレクター攻撃">DNSリフレクター攻撃&lt;a class="td-heading-self-link" href="#dns%e3%83%aa%e3%83%95%e3%83%ac%e3%82%af%e3%82%bf%e3%83%bc%e6%94%bb%e6%92%83" aria-label="Heading self-link">&lt;/a>&lt;/h3>&lt;p>DNSを利用したDoS攻撃の一つ&lt;/p>
&lt;p>送信元IPアドレスを偽った問い合わせをフルリゾルバーや権威サーバーに送ることでそれらのサーバーが応答を攻撃対象に送りサービス不能の状態に陥らせる&lt;/p>
&lt;p>&lt;strong>対策&lt;/strong>&lt;/p>
&lt;p>RRL(Response Rate Limiting)の導入&lt;/p></description></item><item><title>[検証]DockerのMulti-stage builds</title><link>https://yoshihiroshu.com/blog/docker-multi-stage-builds/</link><pubDate>Sat, 18 Mar 2023 12:00:00 +0900</pubDate><guid>https://yoshihiroshu.com/blog/docker-multi-stage-builds/</guid><description>&lt;div>&lt;a id="td-block-0" class="td-offset-anchor">&lt;/a>&lt;/div>
&lt;section class="row td-box td-box--white td-box--height-auto">
&lt;div class="col">
&lt;div class="container">
&lt;h2 id="背景">背景&lt;a class="td-heading-self-link" href="#%e8%83%8c%e6%99%af" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;p>DockerImageのMulti-stage buildsをするとサイズがどのくらい落ちるか気になったので、検証しました。&lt;/p>
&lt;h2 id="対象としている人">対象としている人&lt;a class="td-heading-self-link" href="#%e5%af%be%e8%b1%a1%e3%81%a8%e3%81%97%e3%81%a6%e3%81%84%e3%82%8b%e4%ba%ba" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;ul>
&lt;li>Docker学習中の人&lt;/li>
&lt;li>Docker Imageを実装している人&lt;/li>
&lt;/ul>
&lt;h2 id="実験結果">実験結果&lt;a class="td-heading-self-link" href="#%e5%ae%9f%e9%a8%93%e7%b5%90%e6%9e%9c" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;p>一目瞭然ですね。
まさかの約370MBの違いもありました。&lt;/p>
&lt;p>Goのベースイメージを採用したDockerImage
&lt;a href="https://yoshihiroshu.com/">golang:1.19&lt;/a>をベースイメージとして使っています。
&lt;img alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2083780/1d9bebbb-bb78-5145-1a7b-150fa1899955.png">&lt;/p>
&lt;p>Multi-stage buildsを採用したDockerImage
&lt;a href="https://hub.docker.com/_/scratch">scratch&lt;/a>をベースイメージとして使っています。
&lt;img alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2083780/c0f9912f-5208-06f9-b60b-5ccae2d97e99.png">&lt;/p>
&lt;h2 id="それぞれのdockerimage">それぞれのDockerImage&lt;a class="td-heading-self-link" href="#%e3%81%9d%e3%82%8c%e3%81%9e%e3%82%8c%e3%81%aedockerimage" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;p>Goのベースイメージを採用したDockerImage&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Dockerfile" data-lang="Dockerfile">&lt;span class="line">&lt;span class="cl">&lt;span class="k">FROM&lt;/span>&lt;span class="s"> golang:1.19&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">WORKDIR&lt;/span>&lt;span class="s"> /usr/src/app&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">COPY&lt;/span> . ./&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">RUN&lt;/span> go mod download &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> go mod verify&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">EXPOSE&lt;/span>&lt;span class="s"> 8000&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">CMD&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;go&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;run&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;./cmd/main.go&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Multi-stage buildsを採用したDockerImage&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-Dockerfile" data-lang="Dockerfile">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># syntax=docker/dockerfile:1&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">FROM&lt;/span>&lt;span class="s"> golang:1.19 as builder&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">WORKDIR&lt;/span>&lt;span class="s"> /usr/src/app&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">COPY&lt;/span> ./backend/go.mod ./backend/go.sum ./&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">RUN&lt;/span> go mod download &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> go mod verify&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">COPY&lt;/span> ./backend .&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">RUN&lt;/span> &lt;span class="nv">CGO_ENABLED&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="m">0&lt;/span> go build -o binary ./cmd/main.go&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">FROM&lt;/span>&lt;span class="s"> scratch&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">WORKDIR&lt;/span>&lt;span class="s"> /usr/src/app&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># scratch doesn&amp;#39;t have timezone.&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">COPY&lt;/span> --from&lt;span class="o">=&lt;/span>builder /usr/share/zoneinfo/Asia/Tokyo /usr/share/zoneinfo/Asia/Tokyo&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">COPY&lt;/span> --from&lt;span class="o">=&lt;/span>builder /usr/src/app/binary /usr/src/app/binary&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">COPY&lt;/span> ./backend/configs.yaml .&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">EXPOSE&lt;/span>&lt;span class="s"> 8080&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">CMD&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;./binary&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
&lt;/div>
&lt;/section></description></item><item><title>Kubernetesリソースメモ</title><link>https://yoshihiroshu.com/blog/kubenertes-resource/</link><pubDate>Wed, 18 Jan 2023 12:00:00 +0900</pubDate><guid>https://yoshihiroshu.com/blog/kubenertes-resource/</guid><description>&lt;div>&lt;a id="td-block-0" class="td-offset-anchor">&lt;/a>&lt;/div>
&lt;section class="row td-box td-box--white td-box--height-auto">
&lt;div class="col">
&lt;div class="container">
&lt;h2 id="背景">背景&lt;a class="td-heading-self-link" href="#%e8%83%8c%e6%99%af" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;p>以外と忘れがちなリソースについて、まとめました。&lt;/p>
&lt;h2 id="対象としている人">対象としている人&lt;a class="td-heading-self-link" href="#%e5%af%be%e8%b1%a1%e3%81%a8%e3%81%97%e3%81%a6%e3%81%84%e3%82%8b%e4%ba%ba" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;p>Kubernetesを学習途中の人、またこれからKubernetesを学習しようとしている人&lt;/p>
&lt;h1 id="リソース">リソース&lt;a class="td-heading-self-link" href="#%e3%83%aa%e3%82%bd%e3%83%bc%e3%82%b9" aria-label="Heading self-link">&lt;/a>&lt;/h1>&lt;h2 id="pod">Pod&lt;a class="td-heading-self-link" href="#pod" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;p>PodはKubernetesにデプロイ出来る最小単位&lt;/p>
&lt;ul>
&lt;li>コンテナやボリュームの集まり&lt;/li>
&lt;/ul>
&lt;h2 id="deployment">Deployment&lt;a class="td-heading-self-link" href="#deployment" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;ul>
&lt;li>新しいReplicaSetを作成したり、既存のDeploymentを削除して新しいDeploymentで全てのリソースを適用することができる&lt;/li>
&lt;/ul>
&lt;h2 id="replicaset">ReplicaSet&lt;a class="td-heading-self-link" href="#replicaset" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;ul>
&lt;li>どんな時でも指定された数のPodのレプリカが稼働することを保証する&lt;/li>
&lt;li>&lt;code>spec.template&lt;/code>をハッシュ値で管理しているため、ロールアップ・ダウンによる変更に即座に対応できる。&lt;/li>
&lt;/ul>
&lt;h2 id="ingress">Ingress&lt;a class="td-heading-self-link" href="#ingress" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;ul>
&lt;li>IngressはHTTPやHTTPSの外部アクセスを制御するオブジェクト&lt;/li>
&lt;li>Load Balancerの役割をしている。&lt;/li>
&lt;/ul>
&lt;h2 id="service">Service&lt;a class="td-heading-self-link" href="#service" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;ul>
&lt;li>動的にIPAddressが変更されるPodへの接続を解決してくれる抽象的なオブジェクト&lt;/li>
&lt;li>Podの集合で実行されているアプリケーションをネットワークサービスとして公開する抽象的な方法&lt;/li>
&lt;/ul>
&lt;p>役割&lt;/p>
&lt;ul>
&lt;li>Pod,Nodeの存在を抽象化し、Podとの通信に単一のエンドポイントを提供する&lt;/li>
&lt;/ul>
&lt;h2 id="volumeについて">Volumeについて&lt;a class="td-heading-self-link" href="#volume%e3%81%ab%e3%81%a4%e3%81%84%e3%81%a6" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;p>コンテナのデータは一時的なもので、Pod/コンテナが削除されるか、コンテナがクラッシュした場合コンテナのデータは消えてしまう。
そこでVolumeを使う&lt;/p>
&lt;ul>
&lt;li>メリット
&lt;ul>
&lt;li>Volumeはデータの永続化をしてくれる。 永続化したいデータは指定したVolumeに保存することで削除やクラッシュした際でもデータが残る。&lt;/li>
&lt;li>また、Volumeは別の目的でも使用される。それはPod内でのコンテナ間のデータ共有だ。&lt;/li>
&lt;li>Pod内のコンテナはVolumeを通してデータを共有することが出来る。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="種類">種類&lt;a class="td-heading-self-link" href="#%e7%a8%ae%e9%a1%9e" aria-label="Heading self-link">&lt;/a>&lt;/h3>&lt;ul>
&lt;li>emptyDir
&lt;ul>
&lt;li>Podがノードに割り当てられたときに最初に作成され、そのPodがそのノードで実行されている限り存在する&lt;/li>
&lt;li>名前が示すようにemptyDirボリュームは最初は空&lt;/li>
&lt;li>Podが削除された際に対象のVolumeのデータも削除される。 よってPod内のコンテナ間のデータ共有のみで使用&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>hostPath
&lt;ul>
&lt;li>データが永続化されている(Podが削除されてもデータは消されない)&lt;/li>
&lt;li>Kubernetesが実行されているサーバーにデータが置いてある&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="configmap">ConfigMap&lt;a class="td-heading-self-link" href="#configmap" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;ul>
&lt;li>機密性のないデータをキーと値のペアで保存するために使用されるAPIオブジェクト&lt;/li>
&lt;/ul>
&lt;h2 id="secret">Secret&lt;a class="td-heading-self-link" href="#secret" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;ul>
&lt;li>Secretとは、パスワードやトークン、キーなどの少量の機密データを含むオブジェクト&lt;/li>
&lt;li>PodがSecretを使う方法は3種類がある。
&lt;ul>
&lt;li>ボリューム内のファイルとして、Podの単一または複数のコンテナにマウントする&lt;/li>
&lt;li>コンテナの環境変数として利用する&lt;/li>
&lt;li>Podを生成するためにkubeletがイメージをpullするときに使用する&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="horizontalpodautoscaler">HorizontalPodAutoscaler&lt;a class="td-heading-self-link" href="#horizontalpodautoscaler" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;ul>
&lt;li>Deployment、ReplicaSetまたはStatefulSetといったレプリケーションコントローラ内のPodの数を、観測されたCPU使用率（もしくはベータサポートの、アプリケーションによって提供されるその他のメトリクス）に基づいて自動的にスケールさせる&lt;/li>
&lt;li>podの負荷に応じて自動的にpodの数を増減させる&lt;/li>
&lt;/ul>
&lt;h2 id="poddisruptionbudget">PodDisruptionBudget&lt;a class="td-heading-self-link" href="#poddisruptionbudget" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;ul>
&lt;li>Podの最小の有効状態や最大の無効状態の数を指定する&lt;/li>
&lt;li>Podの管理対象はLabelSelectorで指定する&lt;/li>
&lt;li>フィールドのメモ
&lt;ul>
&lt;li>spec.maxUnavailable : Eviction実行時にPodを無効状態にしていい最大数を指定する。絶対値か百分率で指定する。&lt;/li>
&lt;li>spec.minAvailable : Eviction実行時にPodを有効状態にしておく最小数を指定す る。絶対値か百分率で指定する。&lt;/li>
&lt;li>spec.selector : このBudgetを適用する対象のPodを選択するLabelSelectorを指定&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="cronjob">CronJob&lt;a class="td-heading-self-link" href="#cronjob" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;ul>
&lt;li>CronJobはJobをcronのように定期実行するためのKubernetesのWorkloadリソース
&lt;ul>
&lt;li>時間ベースのスケジュールでJobを作成するKubernetesオブジェクト&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>concurrencyPolicy Jobの並行実行についてのポリシーを指定できる
&lt;ul>
&lt;li>Allow
&lt;ul>
&lt;li>並行なJobの実行を許可するポリシー&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Forbid
&lt;ul>
&lt;li>前回のJobがまだ実行中で完了してない場合、スケジュールされたJobはスキップされる&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Replace
&lt;ul>
&lt;li>前回のJobがまだ実行中で完了してない場合、前回のJobをキャンセルし新しくスケジュールされるJobに置き換える&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="job">Job&lt;a class="td-heading-self-link" href="#job" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;ul>
&lt;li>一つ以上のPodを作成することである特定数のPodが正常終了するまでリトライしながら処理を実行するKubernetesのWorkloadリソース
&lt;ul>
&lt;li>Podの実行が失敗したり削除された場合はJobは新たにPodを起動する&lt;/li>
&lt;li>平行に複数のPodを起動することも可能&lt;/li>
&lt;li>指定された数が正常に終了した際にJobが完了&lt;/li>
&lt;li>Jobを削除するとそのJobによって作成されたPodも削除される&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="namespace">Namespace&lt;a class="td-heading-self-link" href="#namespace" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;ul>
&lt;li>同一の物理クラスター上で複数の仮想クラスターの動作をサポートする
&lt;ul>
&lt;li>&lt;code>kubectl api-resources --namespaced=true&lt;/code>でどのリソースが適応なのか確認できる&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h1 id="おまけ">おまけ&lt;a class="td-heading-self-link" href="#%e3%81%8a%e3%81%be%e3%81%91" aria-label="Heading self-link">&lt;/a>&lt;/h1>&lt;p>Manifestについて簡単なメモです。&lt;/p></description></item><item><title>Dockerのdepends onについて</title><link>https://yoshihiroshu.com/blog/docker-depends-on/</link><pubDate>Tue, 17 Jan 2023 12:00:00 +0900</pubDate><guid>https://yoshihiroshu.com/blog/docker-depends-on/</guid><description>&lt;div>&lt;a id="td-block-0" class="td-offset-anchor">&lt;/a>&lt;/div>
&lt;section class="row td-box td-box--white td-box--height-auto">
&lt;div class="col">
&lt;div class="container">
&lt;h2 id="背景">背景&lt;a class="td-heading-self-link" href="#%e8%83%8c%e6%99%af" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;p>Dockerの&lt;code>depends_on&lt;/code>について、簡単に学んだことをまとめました。&lt;/p>
&lt;h2 id="対象としている人">対象としている人&lt;a class="td-heading-self-link" href="#%e5%af%be%e8%b1%a1%e3%81%a8%e3%81%97%e3%81%a6%e3%81%84%e3%82%8b%e4%ba%ba" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;p>Dockerについて、一通り学習したことがある人&lt;/p>
&lt;h2 id="depends_on">depends_on&lt;a class="td-heading-self-link" href="#depends_on" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;p>サービス間の依存関係を指定できる&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-docker-compose.yaml" data-lang="docker-compose.yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">services&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">service_a&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">busybox&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">service_b&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">busybox&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c"># `service_b` を `service_a` に依存させる&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">depends_on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">service_a&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>service_b を service_a に依存させることができます&lt;/p>
&lt;ul>
&lt;li>docker-compose up: service_a → service_b の順に起動する&lt;/li>
&lt;li>docker-compose run: （ docker-compose up と同じ）&lt;/li>
&lt;li>docker-compose stop: service_b → service_a の順に停止する&lt;/li>
&lt;/ul>
&lt;h2 id="指定パターン">指定パターン&lt;a class="td-heading-self-link" href="#%e6%8c%87%e5%ae%9a%e3%83%91%e3%82%bf%e3%83%bc%e3%83%b3" aria-label="Heading self-link">&lt;/a>&lt;/h2>&lt;ul>
&lt;li>Short syntax （リスト）
&lt;ul>
&lt;li>依存先のサービス名を単純に記述するだけ&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-docker-compose.yaml" data-lang="docker-compose.yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">depends_on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">service_a&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>Long syntax （オブジェクト）
&lt;ul>
&lt;li>依存関係にあるサービスをオブジェクト形式で記述するもの&lt;/li>
&lt;li>この方法では依存先に加えて「条件」を指定することができます&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-docker-compose.yaml" data-lang="docker-compose.yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">depends_on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">service_a&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">condition&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">service_started&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>条件の指定には condition を使用
condition にデフォルト値は無いため、 long syntax を選ぶ場合は必ず指定する必要があり&lt;/p></description></item></channel></rss>