1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[5/5] GiteaでCI/CDパイプラインを構築する デプロイ編

1
Last updated at Posted at 2026-05-09

はじめに

この記事はGiteaを使ったCI/CDパイプラインの構築方法を展開する連載の一つである。

連載の各記事へは以下からジャンプできる。

  1. Giteaインストール編
  2. アプリケーション構築編
  3. テスト編
  4. ビルド編
  5. デプロイ編

CI/CDパイプラインでデプロイする

この記事では以下の赤枠部である、デプロイの自動実行をやってみよう。

アプリケーションのデプロイ方法は多種多様である。クラウド環境にデプロイするかもしれないし、オンプレミス環境にデプロイするかもしれない。

今回は例としてSSHを使ってオンプレミス環境のサーバーにデプロイする想定で進めるが、デプロイ手順がCLIで完結するなら今回紹介する方法の応用で環境を問わずデプロイを自動化できる。

Workflowにデプロイのジョブを追加する

.gitea/workflows/workflow.ymldeployのジョブを追加する。

このジョブはサーバーへSSHで接続し、Dockerイメージをコンテナとして実行する。

.gitea/workflows/workflow.yml
 name: Workflow
 on:
   push:
     branches:
       - main # mainブランチに対して実行する
 env:
   NODE_VERSION: "24.14.1" # 使用するNode.jsのバージョンを定義する
 jobs:
   typecheck:
     runs-on: ubuntu-latest
     steps:
       - name: Checkout
         uses: actions/checkout@v5
       - name: Use Node.js
         uses: actions/setup-node@v4
         with:
           node-version: ${{ env.NODE_VERSION }}
       - name: Install dependencies
         run: npm ci
       - name: Run typecheck
         run: npm run typecheck
   test:
     needs: typecheck # typecheckが通ったら実行する
     runs-on: ubuntu-latest
     steps:
       - name: Checkout
         uses: actions/checkout@v5
       - name: Use Node.js
         uses: actions/setup-node@v4
         with:
           node-version: ${{ env.NODE_VERSION }}
       - name: Install dependencies
         run: npm ci
       - name: Run test
         run: npm run test
   build:
     runs-on: ubuntu-latest
     needs: [typecheck, test] # typecheckとtestが通ったら実行する
     steps:
       - name: Checkout
         uses: actions/checkout@v5
       - name: Use Node.js
         uses: actions/setup-node@v4
         with:
           node-version: ${{ env.NODE_VERSION }}
       - name: Set up QEMU
         uses: docker/setup-qemu-action@v3
       # Docker BuildxにHTTPのコンテナレジストリへのpushを許可する
       - name: Set up Docker Buildx
         uses: docker/setup-buildx-action@v3
         with:
           buildkitd-config-inline: |
             [registry."${{ vars.REGISTRY_ENDPOINT }}"]
               http = true
               insecure = true
       # コンテナレジストリへの認証情報を設定する
       - name: Log in to Gitea container registry
         run: |
           mkdir -p ~/.docker
           AUTH=$(echo -n "${{ gitea.actor }}:${{ secrets.PERSONAL_ACCESS_TOKEN }}" | base64 -w 0)
           echo "{\"auths\":{\"${{ vars.REGISTRY_ENDPOINT }}\":{\"auth\":\"$AUTH\"}}}" > ~/.docker/config.json
       - name: Build and push
         run: |
           IMAGE_NAME=$(node -p "require('./package.json').name")
           TAG_NAME=$(node -p "require('./package.json').version")
           docker buildx build \
             --platform linux/amd64,linux/arm64 \
             --tag ${{ vars.REGISTRY_ENDPOINT }}/${{ gitea.repository_owner }}/$IMAGE_NAME:$TAG_NAME \
             --tag ${{ vars.REGISTRY_ENDPOINT }}/${{ gitea.repository_owner }}/$IMAGE_NAME:latest \
             --cache-from type=registry,ref=${{ vars.REGISTRY_ENDPOINT }}/${{ gitea.repository_owner }}/$IMAGE_NAME:buildcache \
             --cache-to type=registry,ref=${{ vars.REGISTRY_ENDPOINT }}/${{ gitea.repository_owner }}/$IMAGE_NAME:buildcache,mode=max \
             --provenance=false \
             --push \
             .
+  deploy:
+    runs-on: ubuntu-latest
+    needs: [typecheck, test, build]
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v5
+      - name: Use Node.js
+        uses: actions/setup-node@v4
+        with:
+          node-version: ${{ env.NODE_VERSION }}
+      - name: Prepare SSH Key
+        run: |
+          # ジョブ実行用のコンテナにSSHの設定をしてやる必要がある
+          mkdir ~/.ssh && chmod 0700 ~/.ssh
+          echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
+          chmod 0400 ~/.ssh/id_rsa
+          ssh-keyscan -p22 -H ${{ vars.DEPLOYMENT_HOST }} > ~/.ssh/known_hosts
+      - name: Deploy
+        run: |
+          IMAGE_NAME=$(node -p "require('./package.json').name")
+          ssh ${{ vars.DEPLOYMENT_USER }}@${{ vars.DEPLOYMENT_HOST }} "
+            docker pull ${{ vars.REGISTRY_ENDPOINT }}/${{ gitea.repository_owner }}/$IMAGE_NAME:latest &&
+            docker stop $IMAGE_NAME;
+            docker rm $IMAGE_NAME;
+            docker run -d --name $IMAGE_NAME -p 3030:3000 ${{ vars.REGISTRY_ENDPOINT }}/${{ gitea.repository_owner }}/$IMAGE_NAME:latest
+          "

deployのジョブでは以下のことを行っている。

  • リポジトリをチェックアウトする
  • Node.js環境を用意する
  • SSHの設定を行う
  • デプロイ先へSSH接続し、Dockerイメージのプルを行ったあとコンテナとして実行する

リポジトリのSettingsにあるActions-Variablesからデプロイ先サーバーのIPアドレスとユーザー名を追加する。これはSSHの接続先になる。

リポジトリのSettingsにあるActions-Secretsからデプロイ先サーバーのSSHの秘密鍵を登録する。(秘密鍵の内容は別途デプロイ先サーバーにSSH接続し、cat ~/.ssh/id_rsaなどを実行することで確認できる)

末尾には改行を入れること。これをしないと接続に失敗する。

デプロイ先サーバーからGiteaに登録されたDockerイメージを参照できるようにする

前回の記事に書いたとおり、Dockerはデフォルトの設定ではHTTPのレジストリと通信しようとするとエラーになる。これはデプロイ先サーバーでも同様である。

デプロイ先サーバーの/etc/docker/daemon.jsonに以下の設定をマージする。

/etc/docker/daemon.json
{
  "insecure-registries": ["xxx.xxx.xxx.xxx:yyyy"]
}

Dockerデーモンを再起動する。

sudo systemctl restart docker.service docker.socket

GiteaへプッシュしたときCI/CDパイプラインが実行されることを確認する。

Webブラウザでhttp://${デプロイ先サーバーのIPアドレス}:3030にアクセスしたとき、1+1の結果が返ってきたらデプロイに成功している。

仕様変更に対応する

ここまで長い道のりを辿ってCI/CDパイプラインを構築してきた。

機能追加や仕様変更でその効果を実感することができる。

足し算を1+1から1+2に変更しよう。

src/app.ts"
 import { Hono } from "hono";
 import { sum } from "./sum.js";

 export const app = new Hono();

 /**
  * 足し算API
  */
 app.get("/sum", (c) => {
+  return c.json({ result: sum(1, 2) });
 });

バージョンも上げておこう。

package.json
 {
   "name": "cicd-example",
   "type": "module",
+  "version": "1.1.0",
   "scripts": {
     "dev": "tsx watch src/index.ts",
     "build": "tsc",
     "start": "node dist/index.js",
     "typecheck": "tsc --noemit",
     "test": "vitest"
   },
   "dependencies": {
     "@hono/node-server": "^1.19.14",
     "hono": "^4.12.17"
   },
   "devDependencies": {
     "@types/node": "^20.11.17",
     "tsx": "^4.7.1",
     "typescript": "^5.8.3",
     "vitest": "^4.1.5"
   }
 }

リポジトリへプッシュする。

$ git add -A
$ git commit -m "足し算を変更した"
$ git push

CI/CDパイプラインが自動実行される。内容を確認すると、テストで失敗していることがわかる。

テストのジョブを詳しく見るとAPIの戻り値が期待値と異なることがわかる。テストの期待値の更新を忘れていたようだ。

テストが失敗しているのでDockerイメージのビルドやデプロイは行われていない。

テストコードの期待値を更新する。

src/app.test.ts
 import { describe, expect, test } from "vitest";
 import { app } from "./app.js";

 describe("足し算API", () => {
   test("正しい足し算の結果を得られること", async () => {
     const response = await app.request("/sum");

     // HTTPステータスコードが200であること
     expect(response.status).toBe(200);

     // 足し算の結果が期待値と一致すること
     const body = await response.json();
+    expect(body).toEqual({ result: 3 });
   });
 });

再度リポジトリへプッシュする。

$ git add src/app.test.ts
$ git commit -m "足し算のテストコードを見直した"
$ git push

CI/CDパイプラインが自動実行される。今度はテストが通り、ビルドもデプロイも成功する。

Webブラウザでhttp://${デプロイ先サーバーのIPアドレス}:3030にアクセスしたとき、1+2の結果が返ってくることから、最新のアプリケーションがデプロイされていることがわかる。

振り返り

  • Gitea ActionsのCI/CDパイプラインでアプリケーションをデプロイすることができた

リポジトリ

最終形のリポジトリを以下に展開する。

おわりに

Giteaを使ったCI/CDパイプラインを構築し、テスト・ビルド・デプロイを自動化することができた。

今回の記事では題材にTypeScriptのWebアプリケーションを選んだが、学んだことを応用すればPythonでの開発であってもビルドがWindows向けのバイナリであってもCI/CDパイプラインを構築できる。

自動化によって浮いた時間は開発にも使えるし、別分野の学習にも使える。素晴らしいことだ。

1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?