3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ネットワークのCI/CDをGithub Actionsで実装する

3
Last updated at Posted at 2026-02-28

はじめに

この記事は、こちらの記事に影響されてネットワークのCI/CDを真面目に考えてみようということで書いています。

※この記事は2本立てのうちの2本目です。詳細が気になる方はまずこちらをご覧ください。

目的

前回の記事でcontainerlab, Ansible, NAPALM + pytestを使ってネットワークのテストを行う基盤を作成しました。これのおかげで、プログラミング言語からネットワーク状態の検証ができるようになりました。
つまり、ソフトウェア開発と同様にCI/CDの恩恵を受けられるようになるということです。
今回はGithub Actionsを使って一連のフローを自動化(CI)し、本番想定の環境にデプロイ(CD)するところまで作ってみます。

とはいえ、流石にネットワーク機器に全自動CI/CDフローを適用するのは怖いので、デプロイ前に手動での承認を必須にしようと思います。

最終形態としては以下のようになります。

mainブランチに PR作成 or push
        ↓
      CI実行
   - ユニットテスト
   - containerlabデプロイ
   - Ansibleで設定投入
   - ネットワーク状態のテスト
        ↓
   手動承認 (Environment Protection)
        ↓
      CD実行
   - 本番環境(想定)にデプロイ

リポジトリ

ディレクトリ構成(再掲)

network-cicd/
  ├── ansible/
  ├── containerlab/
  ├── config/
  ├── src/
  ├── tests/
  └── desired_state.yml

Pythonのパッケージマネージャはuvを利用します。

Actions実行環境を作る

ネットワークのCDを行うということで、社内のネットワークにアクセスできる環境でActionsを動かす必要があります。しかし、通常ネットワーク機器はSaaSであるGithubからアクセスできないため、self-hosted runnerを利用します。
こちらの記事を参考に設定しました。

CIを作る

解説は後回しで、まずはいったん完成したものを貼ります。

.github/workflows/actions-ci.yml
name: CI Pipeline

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

jobs:
  test-fabric:
    runs-on: self-hosted
    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Install uv
        uses: astral-sh/setup-uv@v7

      - name: Install the project
        run: |
          uv sync --locked --all-extras --dev
          uv pip install -e .

      - name: Run unit tests
        run: uv run pytest tests/unit/

      - name: Install containerlab
        run: curl -sL https://containerlab.dev/setup | sudo -E bash -s "all"

      - name: Cleanup existing containerlab topology
        run: |
          cd containerlab/
          containerlab destroy || true

      - name: Deploy containerlab topology
        run: |
          cd containerlab/
          containerlab deploy

      - name: Deploy configurations
        run: |
          cd ansible/
          uv run ansible-playbook playbooks/deploy.yml -i inventory.dev.yml

      - name: Sleep for 180 seconds to allow the topology to stabilize
        run: sleep 180

      - name: Run fabric tests
        run: uv run pytest tests/fabric/

      - name: Cleanup current containerlab topology
        run: |
          cd containerlab/
          containerlab destroy

CIで実現したいこと

実現したいのは以下のことです。

  • ユニットテスト実行: Pythonコード自体の正常性チェック
  • containerlab起動: 検証環境の立ち上げ
  • Ansible実行: 設定投入
  • ネットワーク状態のテスト実行: fabricの正常性チェック

解説

前半

jobs:
  test-fabric:
    runs-on: self-hosted
    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Install uv
        uses: astral-sh/setup-uv@v7

      - name: Install the project
        run: |
          uv sync --locked --all-extras --dev
          uv pip install -e .

      - name: Run unit tests
        run: uv run pytest tests/unit/

      - name: Install containerlab
        run: curl -sL https://containerlab.dev/setup | sudo -E bash -s "all"

ここでは利用するツールたちの準備をしています。
runs-on: self-hostedを指定することで、self-hosted runner上でこのパイプラインが動くようになります。

後半

      - name: Cleanup existing containerlab topology
        run: |
          cd containerlab/
          containerlab destroy || true

      - name: Deploy containerlab topology
        run: |
          cd containerlab/
          containerlab deploy

      - name: Deploy configurations
        run: |
          cd ansible/
          uv run ansible-playbook playbooks/deploy.yml -i inventory.dev.yml

      - name: Sleep for 180 seconds to allow the topology to stabilize
        run: sleep 180

      - name: Run fabric tests
        run: uv run pytest tests/fabric/

      - name: Cleanup current containerlab topology
        run: |
          cd containerlab/
          containerlab destroy

Cleanup existing containerlab topologyでは、前回のラボが残っていたら削除する処理を実行します。self-hosted runnerなので、もしパイプラインに失敗したらラボ環境が破棄されず残り続けます。なのでフローの中でお掃除してます。

Deploy containerlab topology、Deploy configurationsは環境のデプロイをしています。

Sleep for 180 seconds ...では、設定投入からBGP等が収束するまでの待機時間です。

Run fabric testsでネットワーク状態のテストを行います。

そして最後にCleanup current containerlab topologyで環境を消して終わりです。

承認の仕組みを作る

これはGithubの機能で実現可能です。この記事をもとに設定しました。

CDを作る

まずは成果物です。
CIのファイルと分けたほうが管理しやすいので別ファイルで作っています。

.github/workflows/actions-cd.yml
name: CD Pipeline

on:
  workflow_run:
    workflows:
      - CI Pipeline
    types:
      - completed

jobs:
  deploy-fabric:
    if: >
      github.event.workflow_run.conclusion == 'success' &&
      github.event.workflow_run.event == 'push'

    environment: Production
    runs-on: self-hosted
    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Install uv
        uses: astral-sh/setup-uv@v7

      - name: Install the project
        run: |
          uv sync --locked --all-extras --dev
          uv pip install -e .

      # using containerlab as production environment at this time
      - name: Install containerlab
        run: curl -sL https://containerlab.dev/setup | sudo -E bash -s "all"

      - name: Cleanup existing production topology
        run: |
          cd containerlab-prod/
          containerlab destroy || true

      - name: Deploy production topology
        run: |
          cd containerlab-prod/
          containerlab deploy

      - name: Deploy configurations
        run: |
          cd ansible/
          uv run ansible-playbook playbooks/deploy.yml -i inventory.prod.yml

      - name: Cleanup current production topology
        run: |
          cd containerlab-prod/
          containerlab destroy

解説

起動条件の定義

name: CD Pipeline

on:
  workflow_run:
    workflows:
      - CI Pipeline
    types:
      - completed

ここでは、「CI Pipelineがcompletedになったら」という条件でパイプラインを起動することを宣言しています。

前半

jobs:
  deploy-fabric:
    if: >
      github.event.workflow_run.conclusion == 'success' &&
      github.event.workflow_run.event == 'push'

    environment: Production
    runs-on: self-hosted
    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Install uv
        uses: astral-sh/setup-uv@v7

      - name: Install the project
        run: |
          uv sync --locked --all-extras --dev
          uv pip install -e .

      # using containerlab as production environment at this time
      - name: Install containerlab
        run: curl -sL https://containerlab.dev/setup | sudo -E bash -s "all"

ほぼCIと同じです。if: >ステートメントにて本当にmainブランチにプッシュされたときのみ実行するようにします。これがないと、PR作成時のCI実行でもCDが実行されてしまいます。
今回は本番環境想定のラボを用意して利用します。CDではユニットテストは不要なので書いていません。

後半

      - name: Cleanup existing production topology
        run: |
          cd containerlab-prod/
          containerlab destroy || true

      - name: Deploy production topology
        run: |
          cd containerlab-prod/
          containerlab deploy

      - name: Deploy configurations
        run: |
          cd ansible/
          uv run ansible-playbook playbooks/deploy.yml -i inventory.prod.yml

      - name: Cleanup current production topology
        run: |
          cd containerlab-prod/
          containerlab destroy

これも基本CIと同じです。本番想定のラボを展開している点、Ansibleのインベントリファイルが本番用になっている点が異なっています。
本番想定のラボなのでCI同様、パイプラインの最後に削除していますが実際はこんなことしないようにお願いします…(さすがにいないと思いますが...)

実際に動かしてみる

リポジトリに何らかの変更を加えます。今回はPRを作ってみます。
image.png
実行中...
数分経って検証が終わると画面が変わります。
image.png
マージすると承認を催促するメールが届きます
image.png

承認をするとCDのパイプラインが実行されます。
image.png

さいごに

これにて一通りの実装が全て終わりました。
過去Cisco DevNetでこういったネットワークのコード管理&CI/CDといった構成を見たことがありますが、実際に動くものを見たことがなかったので今回いい感じのものができて満足です。
反省点としてはAnsibleで設定を一括投入しており、差分がわからない点かなと思います。安定性のために、差分だけの投入によって冪等性を確保していきたいです。NAPALMに差分投入機能があるらしいので、色々使って遊んでみたいと思います。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?