2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Dockerに自信があるとはどういう状態か?🤔

Posted at

目次

  1. Dockerfileを書ける
  2. コンテナの中の世界と外の世界を区別できる
  3. Dockerによる開発環境周りでトラブルがあった時に迅速に復旧できる
  4. チームのローカル開発環境を整備できる
  5. CI/CDパイプラインを整備できる

対象読者

  • Docker学習中の方
  • どこまでDockerを学習したらいいか分からない方

1. Dockerfileを書ける

マルチステージビルドで軽量なイメージを作成できる

マルチステージビルドを使用することで、ビルド時に必要な依存関係を最終イメージに含めず、軽量なイメージを作成できます。

例:

# ビルドステージ
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

# 実行ステージ
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
EXPOSE 3000
CMD ["node", "dist/index.js"]

Dockerキャッシュを意識して高速にビルドできる

Dockerはレイヤーキャッシュを活用します。変更頻度の低いファイルを先にコピーすることで、ビルド時間を短縮できます。

なぜなら、変更がない=再ビルドしなくてよいのでここは以前のキャッシュを有効活用したいためです。逆に開発をゴリゴリと進めていくアプリケーションコードは頻繁に変更が起こるので、最後の方にコンテナに持っていくようにします。

例:

FROM ruby:3.2-alpine

WORKDIR /app

# 変更頻度の低い依存関係ファイルを先にコピー
COPY Gemfile Gemfile.lock ./
RUN bundle install

# アプリケーションコードは最後にコピー
COPY . .

EXPOSE 3000
CMD ["rails", "server", "-b", "0.0.0.0"]

2. コンテナの中の世界と外の世界を区別できる

Dockerのネットワークを理解している

docker-composeで繋がれたコンテナ同士ならコンテナ名でアクセス可能だが、コンテナ化していない場合はlocalhostでのアクセスになります。

例:

# docker-compose.yml
version: '3.8'
services:
  web:
    build: .
    ports:
      - "3000:3000"
    environment:
      # webコンテナからdbコンテナにアクセス
      DATABASE_URL: postgresql://postgres:password@db:5432/myapp
    depends_on:
      - db
  
  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_PASSWORD: password
      POSTGRES_DB: myapp
    volumes:
      # コンテナ内のデータをDocker管理領域に永続化するボリュームマウント
      - db_data:/var/lib/postgresql/data

volumes:
  db_data:

Dockerのコンテナの世界とホストマシンの世界を繋げられる

ボリュームマウント → gemやDBのデータの永続化

注意: これはコンテナ内でのデータ永続化の話で、ホストマシンは直接関係ありません。Docker管理領域に保存されます。

例:

services:
  app:
    image: ruby:3.2
    volumes:
      # 名前付きボリュームでgemを永続化
      - bundle_cache:/usr/local/bundle
  
  db:
    image: postgres:15
    volumes:
      # DBデータの永続化
      - postgres_data:/var/lib/postgresql/data

volumes:
  bundle_cache:
  postgres_data:

バインドマウント → コンテナ内とホストマシン内のファイルシステムの同期

例:

services:
  web:
    build: .
    volumes:
      # ホストのカレントディレクトリをコンテナの/appにマウント
      - .:/app
      # node_modulesは除外(コンテナ内のものを使用)
      - /app/node_modules
    ports:
      - "3000:3000"

ポートのマッピング

例:

services:
  web:
    image: nginx:alpine
    ports:
      # ホストの8080ポートをコンテナの80ポートにマッピング
      - "8080:80"
      # ホストの8443ポートをコンテナの443ポートにマッピング
      - "8443:443"

Dockerのコンテナの外の世界とホストマシンの世界を区別できる

# コンテナ内に入る
docker exec -it container_name /bin/bash

# コンテナ内で実行
root@container:/app# ls
root@container:/app# rails console

# ホストマシンで実行
$ docker ps
$ docker logs container_name

3. Dockerによる開発環境周りでトラブルがあった時に迅速に復旧できる

docker process でプロセスの確認

# 実行中のコンテナを確認
docker ps

# すべてのコンテナを確認(停止中のコンテナも含む)
docker ps -a

# コンテナのリソース使用状況を確認
docker stats

Dockerコンテナ、イメージ、ボリューム削除

# rmはremoveで削除の意味

# コンテナの削除
docker rm container_name
docker rm -f container_name  # 強制削除

# イメージの削除
docker rmi image_name
docker image prune  # 未使用イメージの一括削除

# ボリュームの削除
docker volume rm volume_name
docker volume prune  # 未使用ボリュームの一括削除

# すべてのリソースをクリーンアップ
docker system prune -a --volumes

4. チームのローカル開発環境を整備できる

Docker化すべきかどうかの判断

以下のような事項から判断できます:

  • 複数の言語やランタイムバージョンが混在
  • データベースやキャッシュサーバーなど複数のミドルウェアが必要
  • チームメンバーのOS環境が異なる(Mac/Windows/Linux)
  • 新メンバーのオンボーディング時間を短縮したい
  • 本番環境との環境差異を最小化したい

Dockerfileの作成

1. Dockerfileを書ける を参照

例:

FROM ruby:3.2-alpine

# 必要なパッケージのインストール
RUN apk add --no-cache \
    build-base \
    postgresql-dev \
    nodejs \
    yarn \
    tzdata

WORKDIR /app

# 依存関係のインストール
COPY Gemfile Gemfile.lock ./
RUN bundle install

COPY package.json yarn.lock ./
RUN yarn install

# アプリケーションコードのコピー
COPY . .

# アセットのプリコンパイル(本番環境の場合)
# RUN RAILS_ENV=production bundle exec rails assets:precompile

EXPOSE 3000

CMD ["rails", "server", "-b", "0.0.0.0"]

docker-composeの整備

version: '3.8'

services:
  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
      POSTGRES_DB: myapp_development
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data

  web:
    build:
      context: .
      dockerfile: Dockerfile
    command: bundle exec rails server -b 0.0.0.0
    volumes:
      - .:/app
      - bundle_cache:/usr/local/bundle
      - node_modules:/app/node_modules
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgresql://postgres:password@db:5432/myapp_development
      REDIS_URL: redis://redis:6379/0
    depends_on:
      - db
      - redis

volumes:
  postgres_data:
  redis_data:
  bundle_cache:
  node_modules:

テスト環境の整備

# docker-compose.test.yml
version: '3.8'

services:
  db_test:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
      POSTGRES_DB: myapp_test
    tmpfs:
      - /var/lib/postgresql/data  # テストDBはメモリ上で実行

  test:
    build:
      context: .
      dockerfile: Dockerfile
    command: bundle exec rspec
    volumes:
      - .:/app
      - bundle_cache:/usr/local/bundle
    environment:
      RAILS_ENV: test
      DATABASE_URL: postgresql://postgres:password@db_test:5432/myapp_test
    depends_on:
      - db_test

volumes:
  bundle_cache:

テストの実行:

# testサービスの実行をする
# db_testサービスに依存しているのでdb_testサービスも起動してくれる
docker-compose -f docker-compose.test.yml run --rm test

5. CI/CDパイプラインを整備できる

GitHub Actionsコンテナ内でのDockerイメージのbuild

# .github/workflows/ci.yml
name: CI

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main, develop ]

jobs:
  test:
    runs-on: ubuntu-latest
    
    services:
      postgres:
        image: postgres:15-alpine
        env:
          POSTGRES_USER: postgres
          POSTGRES_PASSWORD: password
          POSTGRES_DB: myapp_test
        ports:
          - 5432:5432
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

    steps:
      - uses: actions/checkout@v3
      
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2
      
      - name: Build Docker image
        uses: docker/build-push-action@v4
        with:
          context: .
          push: false
          tags: myapp:test
          cache-from: type=gha
          cache-to: type=gha,mode=max
      
      - name: Run tests
        run: |
          docker run --rm \
            --network host \
            -e RAILS_ENV=test \
            -e DATABASE_URL=postgresql://postgres:password@localhost:5432/myapp_test \
            myapp:test \
            bundle exec rspec

  build:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    
    steps:
      - uses: actions/checkout@v3
      
      - name: Login to Docker Hub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}
      
      - name: Build and push
        uses: docker/build-push-action@v4
        with:
          context: .
          push: true
          tags: |
            myuser/myapp:latest
            myuser/myapp:${{ github.sha }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

まとめ

上記の内容すべてをスラスラ覚えていないにしろ、概念理解とAI使いながら適切に書ける、読めるという感じであれば、Webアプリケーション開発において自信を持っていいのではないかな?と思います。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?