{}const=>[]async()letfn</>var
開発基礎

CI/CDを簡単に:1晩で自動デプロイ

CI/CDの簡単な説明と、GitHub Actionsを使用した自動デプロイのサンプル。

К

Kodik

著者

3分で読める

CI/CD とは何か、そしてなぜ必要なのか

  • CI (Continuous Integration) — すべての編集を自動的に収集してテストします。

  • CD (Continuous Delivery/Deployment) — 成功したら、スタンド/プロダクトに手を使わずにロールアウトします。

利点:手作業によるミスが少ない、リリースが速い、チームにとって透明性が高く、ロールアウトが予測可能。 🧘‍♂️

🔥 10万人以上の学生が参加中

理論を読むのに疲れた?
コーディングの時間だ!

Kodik — 実践でプログラミングを学ぶアプリ。AIメンター、インタラクティブなレッスン、実際のプロジェクト。

🤖 AI 24時間
🎓 修了証
💰 無料
🚀 始める
今日参加

サーバー: 基礎トレーニング (VPS)

# 1) Dockerとcomposeプラグイン(Ubuntu)
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER

# 2) アプリケーションカタログ
sudo mkdir -p /opt/myapp && sudo chown -R $USER:$USER /opt/myapp
cd /opt/myapp

# 3) .env(サーバー上、コミットしない)
cat > .env << 'ENV'
PORT=3000
ENV

# 4) docker-compose.yml
cat > docker-compose.yml << 'YAML'
services:
  web:
    image: registry.example.com/myapp:latest
    env_file: .env
    ports:
      - "80:3000"
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 10s
      timeout: 3s
      retries: 5
YAML

# 5)初回起動(現時点ではCIなし)
docker compose pull && docker compose up -d

Dockerfile(Node/PNPMの最小限の例)

# Dockerfile
FROM node:20-alpine AS deps
RUN corepack enable && corepack prepare pnpm@latest --activate
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN pnpm i --frozen-lockfile

FROM node:20-alpine AS build
WORKDIR /app
COPY --from=deps /app/node_modules node_modules
COPY . .
RUN npm run build

FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=build /app/dist dist
COPY package.json ./
RUN corepack enable && corepack prepare pnpm@latest --activate && pnpm i --prod --frozen-lockfile
EXPOSE 3000
CMD ["node", "dist/server.js"]

GitHub Actions:イメージのビルドとSSHによるデプロイ

リポジトリに.github/workflows/deploy.ymlを追加します。

name: CI/CD Deploy

on:
  push:
    branches: [ "main" ]

permissions:
  contents: read
  packages: write

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to registry
        uses: docker/login-action@v3
        with:
          registry: ${{ secrets.REGISTRY_URL }}
          username: ${{ secrets.REGISTRY_USER }}
          password: ${{ secrets.REGISTRY_PASSWORD }}

      - name: Build & push image
        uses: docker/build-push-action@v6
        with:
          push: true
          context: .
          tags: ${{ secrets.REGISTRY_URL }}/${{ secrets.IMAGE_NAME }}:latest

      - name: Deploy via SSH
        uses: appleboy/ssh-action@v1.0.0
        with:
          host:     ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key:      ${{ secrets.SERVER_SSH_KEY }}
          script: |
            set -e
            cd /opt/myapp
            docker compose pull
            docker compose up -d
            docker image prune -f

秘密: REGISTRY_URL, REGISTRY_USER, REGISTRY_PASSWORD, IMAGE_NAME, SERVER_HOST, SERVER_USER, SERVER_SSH_KEY.

GitLab CI:代替案

# .gitlab-ci.yml
stages: [build, deploy]

variables:
  IMAGE: $CI_REGISTRY_IMAGE:latest

build:
  stage: build
  image: docker:27.0
  services: [ "docker:27.0-dind" ]
  script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
    - docker build -t $IMAGE .
    - docker push $IMAGE
  artifacts:
    expire_in: 1 week
    when: on_success
    paths: []

deploy:
  stage: deploy
  image: alpine:latest
  before_script:
    - apk add --no-cache openssh-client
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
  script:
    - ssh -o StrictHostKeyChecking=no $DEPLOY_USER@$DEPLOY_HOST "
        set -e
        cd /opt/myapp &&
        docker compose pull &&
        docker compose up -d &&
        docker image prune -f
      "
  only:
    - main

ダウンタイムゼロとロールバック

  • Zero‑downtime: restart: unless-stopped + healthcheck + up -d — 新しいコンテナーが起動し、古いコンテナーが終了します。

  • リリースのタグ: :latestに加えて、:v1.4.2をプッシュします。ロールバックが簡単です。

  • Rollback: タグをdocker-compose.ymlに切り替え、pull / up -dを繰り返します。

  • 青/緑のスキーム(簡略化): 2つのサービスweb_blueweb_greenを保持し、Nginxを介してトラフィックのバランスを取ります。

パイプラインでの最小チェック

# GitHub Actionsでのテストステップの例
- name: Install deps & test
  run: |
    npm ci
    npm run test -- --ci

「夜の」CIのしきい値:ユニットテストを実行し、ビルドを収集し、リンター(ESLint/flake8)を通過し、タイプ(tsc/mypy)を確認します。

監視とログ

  • サービスに/health/metrics(Prometheusフォーマット)を追加します。

  • ログの収集: docker logs → Loki/ELK; ステータスコード/潜在性に関するアラート。

  • CI には、テストとリンターのレポートを含むアーティファクトがあり、リグレッションを確認できます。

秘密と安全

  • 秘密はSecrets/Variables CIのみです。.envはサーバー上にあります。

  • SSHパスワードログインを無効にし、キーによるログインを残し、ポートを制限します。

  • 暗号化された形式であっても、リポジトリに秘密鍵を保存しないでください。

🧯 一般的な問題と簡単な解決策

症状

原因

固定

CIがアセンブリで落ちる

RAM不足/タイムアウト

レイヤーキャッシュ、より軽いイメージベース、タイムアウトの増加

アプリケーションが起動しない

ポート/ ENV /移行

.envdocker logs、ヘルスチェックを確認し、移行を実行します

展開が遅い

重いイメージ

マルチステージ、アルパイン、.dockerignore、依存関係のキャッシュ

「私のところで働いている」

異なるバージョンのNode/Python

Docker でバージョンをロックし、ロックファイルを使用する

ディスクが詰まっています

古いイメージ/コンテナ

docker system prune -f、ログのローテーション

アプリで 「コディック — プログラミングの学習」 — 短いレッスンとミニプロジェクト。楽しいレッスンをお届けします!

また、アクティブな テレグラムチャンネル、ここでは素晴らしいアイデアについて話し合い、経験を共有し、課題を一緒に分析します。学習は有益であるだけでなく、楽しいものになります。

合計

CI/CDは「魔法」ではなく、一連の簡単なステップです。イメージをビルドし、レジストリにプッシュし、VPSでサービスを再起動するだけで、手動のルーチンなしで迅速で反復可能なリリースが可能になります。今日から始めれば、明日にはチームは「手動デプロイ」がどのようなものだったかを忘れるでしょう。

GitHub Actions と GitLab CI のどちらで自動デプロイを実行しますか?

🎯先延ばしをやめよう

記事は気に入った?
実践の時間だ!

Kodikでは読むだけでなく、すぐにコードを書く。理論 + 実践 = 本当のスキル。

即座に実践
🧠AIがコードを説明
🏆修了証

登録不要 • カード不要