CI/CD とは何か、そしてなぜ必要なのか
CI (Continuous Integration) — すべての編集を自動的に収集してテストします。
CD (Continuous Delivery/Deployment) — 成功したら、スタンド/プロダクトに手を使わずにロールアウトします。
利点:手作業によるミスが少ない、リリースが速い、チームにとって透明性が高く、ロールアウトが予測可能。 🧘♂️
サーバー: 基礎トレーニング (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_blueとweb_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 /移行 |
|
展開が遅い | 重いイメージ | マルチステージ、アルパイン、.dockerignore、依存関係のキャッシュ |
「私のところで働いている」 | 異なるバージョンのNode/Python | Docker でバージョンをロックし、ロックファイルを使用する |
ディスクが詰まっています | 古いイメージ/コンテナ |
|
アプリで 「コディック — プログラミングの学習」 — 短いレッスンとミニプロジェクト。楽しいレッスンをお届けします!
また、アクティブな テレグラムチャンネル、ここでは素晴らしいアイデアについて話し合い、経験を共有し、課題を一緒に分析します。学習は有益であるだけでなく、楽しいものになります。
合計
CI/CDは「魔法」ではなく、一連の簡単なステップです。イメージをビルドし、レジストリにプッシュし、VPSでサービスを再起動するだけで、手動のルーチンなしで迅速で反復可能なリリースが可能になります。今日から始めれば、明日にはチームは「手動デプロイ」がどのようなものだったかを忘れるでしょう。
GitHub Actions と GitLab CI のどちらで自動デプロイを実行しますか?
