この記事は実際にはグループ内での 2 回目の共有内容です。今回は CI/CD に関するいくつかの問題や進化の過程で直面する必要がある問題について話したいと思います。もちろん、この記事は初心者向けの内容と少しの暴論を含んでいますので、気軽に見てください。
開宗明義、定義先行#
私たちが何かを話す前に、その事物の定義を示す必要があります。それでは、今日話す CI と CD の定義を見てみましょう。
まず、CI は Continuous Integration の略で、日本語では継続的インテグレーションと表現されます。一方、CD は一般的な文脈では 2 つの意味を持つ可能性があります:Continuous Delivery または Continuous Deployment で、それに対応する表現は継続的デリバリー / 継続的デプロイメントです。ここでは Brent Laster がWhat is CI/CD?1で示した定義を借用します。
継続的インテグレーション(CI)は、製品のソースコードが変更される際に、自動的に検出、プル、ビルド、(ほとんどの場合)ユニットテストを行うプロセスです。CI はパイプラインを開始する活動です(ただし、特定の事前検証 — しばしば「プレフライトチェック」と呼ばれる — が CI の前に組み込まれることがあります)。
CI の目標は、開発者からの新しい変更が「良い」ものであり、コードベースでのさらなる使用に適していることを迅速に確認することです。
継続的デプロイメント(CD)は、CD パイプラインから出てきたコードのリリースを自動的に取得し、エンドユーザーに提供できるという考え方を指します。ユーザーによるコードの「インストール」方法によっては、クラウドに何かを自動的にデプロイしたり、アプリの更新を提供したり(例えば、電話のアプリ)、ウェブサイトを更新したり、単に利用可能なリリースのリストを更新したりすることを意味する場合があります。
定義を見るだけでは、皆さんはまだ混乱するかもしれませんので、以下ではいくつかの実際の例を使って CI/CD のことを一から整理してみましょう。
Re:0 から構築プロセスを始める#
このタイトルは少し適当な感じがしますが、気にしないでおきましょう。まず、最もシンプルな要求を仮定します。
私たちは Hexo を基にした個人ブログシステムを構築しました。そこには私たちが公開する必要のある記事と、私たちが設定したテーマが含まれています。これを特定のリポジトリに公開する必要があります。
さて、この要求に基づいて、0 から 0 までのプロセスを体験してみましょう(笑)。
原生の構築の始まり#
ここで多くの人が Hexo を選んだ理由を尋ねるかもしれません。理由は簡単です!それが十分にシンプルだからです!
本題に戻りますが、まず Hexo には 2 つのコマンドhexo g
とhexo d
があります。これらは現在のディレクトリ内の Markdown ファイルに基づいて静的なウェブページを生成し、生成された成果物を設定に従って対応するリポジトリにプッシュします。
では、最も原始的な段階での構築プロセスは次のようになります。
- エディタを使って、楽しく記事を書く
- そしてローカル端末で
hexo g && hexo d
を実行する
問題が発生しました。時々ブログを投稿したのに、生成コマンドを実行するのを忘れた場合はどうしますか?または、毎回同じコマンドを繰り返し入力するのが面倒な場合はどうしますか?それでは、全体のプロセスを自動化しましょう。Let's rock!
さらに進んだ構築#
さて、私たちが自動化を完了したと仮定しましょう。現在、ブログを公開するワークフローはどのようになるべきでしょうか。
- Markdown ファイルを作成し、GitHub リポジトリのマスターブランチにプッシュする
- 自動タスクが私たちのブログを構築し、一連の静的ファイルとスタイルを生成する
- 私たちの静的ファイルとスタイルを私たちのサイトのリポジトリ / CDN などのターゲット位置にプッシュする
さて、ここで 2 つの核心的な問題があります。
- コードをプッシュしたときに自動的に構築を開始する
- 構築が完了した後、成果物をプッシュする
それでは、GitHub Action を基にして私たちの自動化構築タスクを設定しましょう。
name: Build And Publish Blog
on:
push:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: '12.x'
- name: Install Package
run: npm install -g hexo-cli && npm install
- name: Generate Html File
run: hexo g
- name: Deploy 🚀
uses: JamesIves/[email protected]
with:
GITHUB_TOKEN: ${{ secrets.PUBLSH_TOKEN }}
BRANCH: gh-pages # アクションがデプロイするブランチ。
FOLDER: public # アクションがデプロイするフォルダ。
この設定は実際に以下のことを実現しています。
- マスターブランチにコードをプッシュしたときに構築をトリガーする
- コードをプルする
- 構築に必要な依存関係をインストールする
- 静的ファイルを生成する
- 静的ファイルをプッシュする
上記のいずれかのステップが失敗した場合、後続のステップの実行はキャンセルされます。実際、このようなシンプルなタスクには CI と CD に含まれる基本要素がすでに含まれています(ここで CD は継続的デリバリー / 継続的デプロイメントを厳密に区別していません)。
- 既存のコードとの継続的な構築と統合
- 統合中に複数のフェーズを区別する。各フェーズは前のフェーズの結果に依存します。
- 構築成果物をデリバリー / デプロイする。デリバリー / デプロイの成功は統合の成功に依存します。
ここで、ブログシステムを私たちのプロジェクトの例に置き換えましょう。Hexo を私たちの Python サービスに置き換え、新しいブログ記事を私たちの新しいコードに置き換え、構築コマンドを mypy/pylint などのチェックツールに置き換えます。見てください、CI/CD は実際にはあなたが想像するような複雑なシステムとは大きく異なるのです。
ここで多くの人がこうした質問をするかもしれません。もしここでこれらのコマンドをオンラインの形式でトリガーせず、ローカルで Git Hook などの形式で実現した場合、これは CI と CD の一種と見なされるのでしょうか?私の視点から見ると、間違いなくそうです。CI/CD の核心的要素は、繰り返し可能で自動化されたタスクを通じて欠陥を早期に露呈させ、人為的要因による不必要な事故を軽減することにあります。
この開発者は過剰に愚かで慎重ではない#
まず、最も基本的な暴論を投げかけ、その後に進めましょう。
誰もが愚かな時期を持っており、その愚かな時期は多くあるかもしれません。
このような暴論の下で、上記のHexo を基にした個人ブログシステムの構築の例を振り返ってみましょう。もし私たちが収束した自動化システムを通じて構築と公開の要求を解決しない場合、どの段階でリスクが発生するでしょうか。
- 最も基本的なこととして、ブログを書き終えた後、構築を忘れ、公開を忘れる
- 例えば、依存関係の Hexo バージョンやテーマバージョンをアップグレードする際に、テストを行わず、構築されたスタイルが無効になる
- Markdown に問題があり、構築が失敗する
- 例えば、複数の人が 1 つのブログを管理する場合、各自がターゲットリポジトリ / CDN の秘密鍵などの情報を保存する必要があり、情報漏洩などが発生する
Hexo を基にした個人ブログシステムの例を日常の開発シーンに切り替えると、私たちが直面する問題はさらに多くなります。いくつかの例を挙げてみましょう。
- 迅速にロールバックできない
- 特定の構築 / 公開記録を追跡できない
- 自動化されたタスクがなく、開発者がテストや lint を実行するのを怠り、コードが劣化する
- ピーク時の公開による事故
うん、これらの問題は皆さんにとって非常に馴染み深いものではありませんか?大体、私は始めて、構築して、事故が起きて、何か言うことがあるのか 23333。
ここまで来て、皆さんは実際に 1 つの問題に気づいていますか?この記事の中で、私は CI と CD を区別していません。私の視点から見ると、CI/CD は本質的に同じ事を実践しているのです。つまり、開発プロセスとデリバリープロセスの収束です。
私の視点から見ると、CI/CD システムを構築する核心的な目標は次のとおりです。
- 収束した入口と自動化されたタスクのトリガーを通じて、人為的要因によるシステムの不安定性をできるだけ軽減する
- 迅速で、複数回、繰り返し可能で、無感知なタスクを通じて、できるだけ早い段階でシステム内の問題を露呈させる
この 2 つの大きな目標の前提の下で、私たちは異なるビジネスシーンに応じて、CI/CD の内容を豊かにするために異なる手段や形式を採用します。これには以下が含まれますが、これに限りません。
- CI 段階での自動化された単体テスト、E2E テストなど
- CI 段階での定期的なナイトビルドなど
- CD 段階での公開管理など
しかし、私たちがどのように CI/CD システムを構築しようとも、またはどのような粒度で CI/CD を選択しようとも、私は合格の CI/CD システムとメカニズムは次のような原則に従う必要があると考えています(個人的なまとめ)。
- 入口の収束、SOP の確立。この点での合意が達成されない場合、開発者が技術的手段を使って CI/CD システムを回避できるなら、私たちは再びこの章のタイトルに戻ることになります(この開発者は過剰に愚かで慎重ではない)。
- ビジネスコードへの非侵入性
- 統合タスク / 公開タスクは必ず自動化され、繰り返し可能であること
- 追跡可能な履歴記録と結果
- 追跡可能な構築統合成果物
- 上から下までのサポート
私がまとめたこれらの原則に従って、以前のブログの公開プロセスを改良してみましょう。
name: Build And Publish Blog
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: '12.x'
- name: Install Package
run: npm install -g hexo-cli && npm install
- name: Generate Html File
run: hexo g
- name: Deploy To Repo🚀
if: ${{ github.ref == 'refs/heads/master'}}
uses: JamesIves/[email protected]
with:
GITHUB_TOKEN: ${{ secrets.PUBLSH_TOKEN }}
BRANCH: gh-pages # アクションがデプロイするブランチ。
FOLDER: public # アクションがデプロイするフォルダ。
- name: Upload to Collect Repo
uses: JamesIves/[email protected]
with:
GITHUB_TOKEN: ${{ secrets.PUBLSH_TOKEN }}
BRANCH: build-${{ github.run_id }} # アクションがデプロイするブランチ。
FOLDER: public # アクションがデプロイするフォルダ。
この変更された構築プロセスでは、PR を粒度として CI プロセスをトリガーし、履歴成果物を保存することを選択しました。そして、マスターブランチにマージされた後に新しい公開プロセスを追加しました。こうすることで、ブログの構築と公開の際に、履歴成果物を通じてフレームワークのアップグレードや新しいブログ記事の操作の正確性を検証できるようになります。また、GitHub Action を利用することで、履歴構築の追跡も非常に良く行えます。
これにより、私の愚かな操作によるさまざまな副作用をできるだけ回避できるようになります(逃)。
攻撃的な構築:終章#
さて、何もなくて驚いているでしょう。
。
。
。
。
ただの冗談です。実際、この記事はここでほぼ終わりです。この記事を通じて、実際に CI/CD システムを構築することは、あまり多くの高度な技術的問題を含まない可能性があることがわかります(極少数のシーンを除いて)。伝統的な Jenkins でも、新しい GitHub Action、GitLab-CI、またはクラウドプロバイダーが提供するサービスでも、ビジネスに適した CI/CD システムを構築するのに役立ちます。しかし、私は以前 Twitter で「CI/CD の構築は往々にして技術的な問題ではなく、制度的な問題であり、むしろ考え方の問題である」と述べました。
したがって、私は私たち全員が自分たちが間違いを犯すという事実を認識し、自分が担当するシステムの開発プロセスとデリバリープロセスをできるだけ収束させ、自動化することを望んでいます。CI/CD が私たちの日常業務の一部として本当に機能するように。
これで、さようなら、さようなら。