GitHub ActionsとDockerによる堅牢なCI/CDパイプラインで、テスト、Dockerイメージのビルド、レジストリへのプッシュ、サーバーへのデプロイを自動化します。このガイドでは本番グレードのパイプラインを構築します。
パイプラインの概要
パイプラインはCI(テスト)、Build(Dockerイメージ)、Push(レジストリへ)、Deploy(サーバーへ)の4つのステージを持ちます。
Pipeline Flow:
git push → GitHub Actions triggered
│
├─ [Job 1] CI: npm test, lint, type-check
│ (runs on all PRs and main pushes)
│
├─ [Job 2] Build: docker build --platform linux/amd64,linux/arm64
│ (runs only on main branch push)
│ Push to ghcr.io/org/app:sha-abc1234
│
└─ [Job 3] Deploy: SSH to server, docker pull + restart
(runs after successful build)
Zero-downtime with blue-green or rolling restartDockerfileのベストプラクティス
適切に構造化されたDockerfileが基礎です。マルチステージビルドにより最終イメージサイズを大幅に削減できます。
# Multi-stage Dockerfile (Node.js example)
# Stage 1: Dependencies
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production && cp -R node_modules /prod_node_modules
RUN npm ci # install ALL deps for building
# Stage 2: Builder
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
# Stage 3: Production runner (minimal image)
FROM node:20-alpine AS runner
WORKDIR /app
# Security: run as non-root user
RUN addgroup --system --gid 1001 nodejs \
&& adduser --system --uid 1001 appuser
# Copy only what's needed for runtime
COPY --from=deps /prod_node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package.json ./
USER appuser
EXPOSE 3000
# Health check for orchestrators
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s \
CMD wget -qO- http://localhost:3000/health || exit 1
CMD ["node", "dist/index.js"]
# Result: ~150MB instead of ~800MB for the same app基本的なCI/CDパイプライン
このワークフローはmainへのプッシュごとにGitHub Container Registryにビルドしてプッシュします。
# .github/workflows/deploy.yml
name: CI/CD Pipeline
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
# Stage 1: Test
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Run lint
run: npm run lint
# Stage 2: Build and Push Docker image
build-push:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
permissions:
contents: read
packages: write
outputs:
image-digest: ${{ steps.build.outputs.digest }}
steps:
- uses: actions/checkout@v4
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} # Auto-provided by GitHub
- name: Extract Docker metadata (tags, labels)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=sha,prefix=sha-
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Docker image
id: build
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
# Stage 3: Deploy to server
deploy:
needs: build-push
runs-on: ubuntu-latest
environment: production # GitHub Environment with protection rules
steps:
- name: Deploy to production server via SSH
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
# Pull latest image
echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin
docker pull ghcr.io/${{ github.repository }}:latest
# Zero-downtime restart
docker compose -f /app/docker-compose.prod.yml up -d --no-deps app
# Verify deployment
sleep 10
docker compose -f /app/docker-compose.prod.yml ps高度なパイプライン機能
本番パイプラインにはマルチプラットフォームビルド、セキュリティスキャン、ロールバック機能が必要です。
# Advanced Pipeline Features
# 1. Multi-platform builds (AMD64 + ARM64)
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build multi-platform image
uses: docker/build-push-action@v5
with:
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
# 2. Security scanning with Trivy
- name: Scan image for vulnerabilities
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
exit-code: '1' # Fail pipeline on critical vulnerabilities
# 3. Semantic versioning with tags
on:
push:
tags:
- 'v*.*.*'
jobs:
release:
steps:
- name: Extract version from tag
id: version
run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
- uses: docker/build-push-action@v5
with:
tags: |
ghcr.io/myorg/myapp:${{ steps.version.outputs.VERSION }}
ghcr.io/myorg/myapp:latest
# 4. Rollback on failure
- name: Deploy with rollback
run: |
PREVIOUS_IMAGE=$(docker inspect --format='{{.Config.Image}}' app-container)
docker pull $NEW_IMAGE
if docker run --rm $NEW_IMAGE node -e "require('./dist/index.js')"; then
docker stop app-container
docker run -d --name app-container $NEW_IMAGE
else
echo "New image failed healthcheck, keeping previous"
exit 1
fiよくある質問
GitHub ActionsでSecretsを保存するには?
リポジトリSettings → Secrets and variables → Actions → New repository secretに移動してください。
ghcr.ioとDocker Hubの違いは?
GitHub Container Registry(ghcr.io)は公開リポジトリは無料でGitHub権限と統合されています。
AMD64とARM64両方のビルドは?
docker/setup-qemu-actionとdocker/setup-buildx-actionを使用し、platforms: linux/amd64,linux/arm64を設定してください。
環境固有のデプロイはどう実装する?
GitHub EnvironmentsでstagingとproductionのEnvironmentsを作成し、保護ルールを設定してください。