この記事はNuco Advent Calendar 2023の9日目の記事です。
はじめに
この記事ではDockerで開発環境を行うために理解してほしい概念と実際の開発環境の構築手順について解説を行います。大きく分けて、
・Dockerの概念理解
・開発環境の構築
これらの章により構成されています。この記事を読むことで、Dockerファイル、イメージ、コンテナ、Docker compose、compose.ymlを理解できるようになることを目指しています。Dockerに触れてみたい、Dockerの理解があやふやという方は参考にしてみてください!
弊社Nucoでは、他にも様々なお役立ち記事を公開しています。よかったら、Organizationのページも覗いてみてください。
また、Nucoでは一緒に働く仲間も募集しています!興味をお持ちいただける方は、こちらまで。
Dockerとは
まず、Dockerに対する理解をしていきましょう。
Dockerとは「コンテナ型の仮想環境を作成、共有、実行するためのプラットフォーム」です。クジラのようなアイコンが特徴的です。
私が最初に勉強をした時に、
「コンテナ型の仮想環境ってなんだ?」
と思ったので、これを解決するために、仮想環境とコンテナについて解説したいと思います。
仮想環境
仮想環境とは、仮想的に構築された環境のことを指します。仮想的という言葉は擬似的という言葉に置き換えられます。例えば仮想環境では、WindowsPC上でLinuxOSを動作させることができます。これは、仮想環境により、LinuxOSが擬似的に再現されているということになります。
コンテナ
コンテナはその名の通り、物流で使用されるコンテナをイメージしてもらって大丈夫です。コンテナという箱の中にアプリケーションに必要なものが詰まっています。
Dockerでは、コンテナ技術を利用して仮想環境を構築しています(コンテナ利用した仮想環境構築の方法で一番広まっているのがDockerです)。このコンテナ技術を利用すると何が嬉しいのか次のDockerのメリットで解説します。
Dockerのメリット
軽量に起動できる
Dockerは従来の仮想環境に比べて軽量に起動することができます。それはコンテナ技術を利用することで実現されています。
図の左側は従来の仮想環境ソフトウェアを用いた場合になります。従来の仮想技術では、仮想化ソフトウェアによりゲストOSが構成され、その上にミドルウェアやアプリケーションが構築されています。そのため、起動するたびにゲストOSを起動する必要がありました。一方Dockerでは、コンテナエンジンを用いて、ゲストOSがあるかのように環境を構築しています。
従来の仮想マシン:仮想化ソフトウェア→ゲストOS→ミドルウェア等
Docker:コンテナエンジン→ミドルウェア等
このようにDockerではゲストOSを起動させる分の処理が簡略化されているため、従来の仮想技術よりも軽量に起動することができます。これにより、従来の仮想技術に比べてハードウェアのリソース削減を行うことができています。
共有のしやすさ
後述しますが、DockerではDockerイメージと呼ばれる、テンプレートのようなものを使用して、コンテナ(実行環境)を構築します。Docker HubなどからDockerイメージをダウンロードすれば、誰でも同じ環境を簡単に構築することができます。
開発の一貫性
開発の現場において、プログラミングなどのソースコードはGithubを用いれば簡単に行うことができます。しかし、プログラミングコードを実行するために、実行環境を整える必要があります。Dockerでは、アプリケーションとその依存関係をまとめ、ほかの環境でも同じように動作するように保証します。つまり開発環境と本番環境で同じコンテナを用いれば動作が保証されるため、開発チームと運用チームで発生する環境のずれにより発生する問題を最小限に抑えることが可能です。
簡単なバージョン管理
Dockerイメージはバージョン管理が容易で、変更履歴を確認し、特定のバージョンに戻すことができます。これにより、アプリケーションのアップデートやロールバックが簡単に行えます。
セキュリティの向上
Dockerはセキュリティスキャンツールと統合しやすく、コンテナイメージが脆弱性を含んでいないかを簡単に確認できます。これにより、セキュリティの問題を素早く検知して対処できます。
迅速な展開とスケーリング
Dockerは従来の仮想技術よりも軽量に起動可能です。これにより、新しいコンテナを迅速にデプロイし、必要に応じスケールアウトをすることができます。
Dockerの基本概念
これまでにDockerの全体的構成について解説しました。次により細かく、Dockerを構成する基本概念について解説したいと思います。ここでは特に、イメージ、コンテナ、レジストリ、Dockerfileについて解説します。Dockerfileは環境構築を行う上で重要なものであるため抑えましょう。
Dockerイメージ
Dockerイメージはコンテナを起動するための設定ファイルをまとめたものとなっています。Dockerイメージを起動することで、コンテナが作成されます。Dockerではこのイメージを共有することで、異なるマシン(PC)上で同じ実行環境(コンテナ)を構築することができます。
より、Dockerイメージの理解を深めるためにDockerイメージの構造について説明します。
Dockerイメージは複数のイメージレイヤと呼ばれる"層"によって構成されています。1つの層に対して1つのミドルウェアが対応します。これらの層は読み取り専用で編集はできません。イメージからコンテナを生成し、コンテナ内でミドルウェアをインストールした場合には、新しい層が追加されることになります。この新しい層は編集可能です。また、コンテナで追加した層を含めて、新たにイメージを作成することもできます。
Dockerコンテナ
今まで説明を行いましたが、コンテナは実際のアプリケーションの動作環境になります。コンテナはイメージを起動することで動かすことができます。私たちはこのコンテナ内で作業を行い、アプリケーションやシステムの開発を行います。
レジストリとは
Dockerレジストリとは、Dockerイメージを保存する場所になります。Docker Hubなどがレジストリに該当します。レジストリにDockerイメージを保存することで、他の人と共有を行ったりすることができます。Docker Hubの利用方法については、こちらの章で解説します。
Dockerfile
DockerfileとはDockerイメージを構築するための設計図のようなものです。つまり、Dockerfileを編集することで、環境構築ができるようになります。
Dockerfileの構文
Dockerfileは命令と引数により構成されます。一行につき一つの命令が与えられ実行する際に1行目から順番で実行されます。
{命令} {引数}
こちらが命令の一例です。
命令 | 使用用途 |
---|---|
FROM | ベースイメージを指定する |
RUN | コマンドを実行する |
CMD | コンテナの実行コマンド |
ENV | 環境変数の指定 |
COPY | ファイルコピー |
FROM
FROMではベースイメージの指定を行います。ベースイメージとは、さきほどのDockerイメージの際に説明したイメージレイヤの最初のレイヤに該当します。つまりイメージはベースイメージから積み上げる形で構成されていきます。ベースイメージには、ベースとなるDockerイメージが入ります。最初の内はベースイメージにはUbuntuやCentOSなどが入るという認識でも大丈夫です。
例えば、ベースイメージにUbuntuにした場合次のように書かれます。
FROM ubuntu:22.04
RUN
RUNでは、対応するディストリビューション(Ubuntu、CentOS、debianなど)の実行コマンドを入力して必要なライブラリなどのインストールを行います。
RUN apt-get update && apt-get install -y
COPY
ファイルのコピーを行います。{src}はコピー元のファイルまたはディレクトリであり、{dest}はコピー先のパスです。
COPY {src} {dest}
WORKDIR
作業ディレクトリを指定することができます。
WORKDIR /app
この場合コンテナ起動時にappディレクトリがカレントディレクトリとなっています。
CMD
CMDでは"コンテナの"実行コマンドを指定できます。CMDを編集することで、実行コマンドの省略を行えます。
全体
Dockerfileの中身をこちらを用いて確認していきましょう。
# ベースイメージを指定
FROM ubuntu:20.04
# 作業ディレクトリを/appに設定
WORKDIR /app
# 環境変数を表示するスクリプトをコピー
COPY print_env.sh .
# スクリプトを実行するコマンド
CMD ["./print_env.sh"]
このコンテナを実行するとprit_env.shが実行されて環境変数が表示されます(print_env.shは別途用意する必要があります)。
一連の流れ
こちらがDockerにおける環境構築の基本的な流れとなっています。まず、Dockerfileを私たちが編集することで、イメージの設計書を作成します。設計書を元に、イメージを作成し、イメージを起動することで、コンテナ(実行環境)を構築します。これがDockerで行われる基本的な流れとなっています。
また、Dockerfileを編集しなくとも、Docker Hubからイメージをダウンロードすることでコンテナを起動することもできます。
Dockerの基本コマンド
イメージ
・Docker Hubからイメージを取得
docker image pull example_image
・Dockerのイメージ一覧の取得
Docker image ls -a
-aはオプションですべてのイメージが表示されます。
・DockerfileからDockerイメージの作成
docker image build -t example_image:1.0 {Dockerfileのパス}
-tのオプションを与えることで、イメージの名前とタグを設定します。タグはバージョンを示したりするのに用います。
・Dockerイメージの削除
docker image rm example_image
rmでDockerイメージの削除を行います。
コンテナ
・コンテナの一覧を表示
docker container ls -a
・コンテナの起動
docker container run -- name example_container
・コンテナの停止
docker container stop example_container
・停止中のコンテナの起動
docker container start example_container
・起動中のコンテナの再起動
docker container restart example_container
・コンテナの削除
docker container rm example_container
基本となるコマンドの一例を紹介しましたが、コマンドはオプションを含め、たくさんあるのでこちらを参考に調べてみてください。
ボリュームと永続性
データ永続性の確保
コンテナ内で管理されているデータはコンテナを削除したときに、消えてしまいます。データを消さないためにも、データの永続性の確保が必要となります。そこで必要となるのがマウントとボリュームです。
マウントとは
コンテナの外にあるデータを、コンテナ内で利用できるようにすることをマウントと呼びます。Dcokerにおいてマウントは3種類あります。
・ボリューム
・バインドマウント
・一時ファイルシステムマウント
この3種類となります。
今回はDockerで推奨されるボリュームに焦点を当てて解説します。
ボリューム(volume)とは
ボリュームはデータを永続する場所のことを指します(USBなどの外付け記憶装置のようなイメージです)。そのため、ボリュームをコンテナに結び付ける(マウント)ことでデータの永続化を行います。またボリュームは複数のコンテナに接続することもできます。
Docker Composeの基本
Dcoker Composeの役割
Dockerを利用した開発では複数のコンテナを起動して、コンテナ間の通信を行う必要があります。例えば、Dockerを利用して、WordPressを実行する場合には、PHPにより構成されたコンテナとデータベースのコンテナを利用する必要があります。いちいち、手動でDockerイメージからコンテナの起動などを行うのは連携するコンテナが増えると面倒になってきます。その手間を解消するために必要となるのが、Docker Composeです。
Docker Composeでは、compose.ymlと呼ばれるDockerに対する指示書を作成します。Dockerはこの指示書に基づいて複数のコンテナを同時に起動します。
YAMLファイルの構文
こちらがWordPressを実現するためのcompose.ymlとなっています。構文の細かな解説は省略しますが、コメントでざっくりと説明を付け加えとくので参考にしてみてください!
version: '3' #Docker-composeのバージョンを指定します
services: #起動するコンテナごとに一つのサービスを定義します。
db: #dbという名前をつけてサービスを定義します
image: mysql:5.7 #イメージの指定
volumes: #パスをボリュームとしてマウントします(ホスト側:コンテナ側のように記載します)
- db_data:/var/lib/mysql
restart: always #再起動ポリシーの設定(alwaysだとコンテナが停止すると常に再起動します)
environment: #環境変数の設定を行います。
MYSQL_ROOT_PASSWORD: somewordpress
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
wordpress:
depends_on: #サービス間の依存関係を指定します(起動するときはdb→wordpress、停止のときは逆順となります)
- db
image: wordpress:latest
ports: #ポートを公開します(ホスト:コンテナで記載します.コンテナのみを指定した場合はホストはランダムに設定されます)
- "8000:80"
restart: always
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
volumes: #ボリュームの設定db_dataという名前のボリュームが定義されます。
db_data:
こちらがリファレンスになるので、他のサービス設定を確認したい方は参考にしてみてください。
Docker Composeの基本コマンド
Docker Composeの基本コマンドを紹介します。
・copose.ymlで記載された各イメージをまとめてビルド
docker-compose build
・コンテナを一括で起動
docker-compose up -d
・コンテナの停止
docker compose stop
・コンテナの再起動
docker compose start
・コンテナをまとめて削除
docker compose down
より、詳細なコマンドはこちらを参考にしてみてください。
開発環境構築の具体的な手順
ここまで長々と説明しましたが、実際に開発環境を構築してみましょう。
すでにあるイメージを使用する場合
DockerHubにはDockerイメージが公開されているため、自分でDockerfileをいじらなくてもイメージを引っ張ってきてコンテナを作成することができます。まずはその方法を紹介します(コマンドをぽちぽちしていけば構築できます)
・Docker Hubからイメージの取得
docker image pull ubuntu
イメージがあることを確認します。
$ docker image ls
・イメージからコンテナの起動
$ docker container run -it -d --name ubuntu-qiita ubuntu
-itはコンテナを対話的なモードで実行するためのオプションです。-dではコンテナがバックグラウンドで実行されるようにします。--nameでコンテナの名前を指定します。
コンテナが作成されていることを確認します。
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3b35a6bedeb5 ubuntu "/bin/bash" 9 minutes ago Up 9 minutes
次のコマンドで起動されたコンテナ内に入ることができます。
$ docker exec -it ubuntu-qiita bash
コンテナ内はこのようになっています。
これでUbuntuの環境構築が完了しました。
コンテナから出る時はexitでコンテナから出ることができます。
exitでコンテナから出てもコンテナ自体は起動したままなので、コンテナを停止させます。
$ docker container stop ubuntu-qiita
このコマンドでコンテナが停止します。
$ docker container rm ubuntu-qiita
このコマンドで停止したコンテナを削除することができます。
Dockerfileから作成
続いて、Dockerfileからイメージを作成して動作させてみましょう。Pythonを実行できるように環境構築を行います。
Docker-Python
└ dockerfile
# ベースイメージを指定
FROM python
RUN apt-get update
RUN pip install --upgrade pip
WORKDIR /Qiita
短いDockerfileになりますが、これだけでPython環境を構築できます。Dockerfileをもとにイメージを作成します。
$ docker build -t python-qiita:latest .
実際にイメージが生成されました。
あとは、先ほどと同様にコンテナを起動してコンテナ内に入れば作業ができます。今回はWORKDIRにQiitaを設定しているため、Qiitaディレクトリがカレントディレクトリとなります。
実際にPythonを実行することができました。
Docker Composeを利用した複数のコンテナ管理
Docker composeを利用して、WordPressの環境を構築してみましょう。
以下のようなディレクトリ構成にします。
Docker-WordPress
└ compose.yml
version: '3'
services:
db:
platform: linux/x86_64 #M1チップマックの場合はこの行を追加してください
image: mysql:5.7
volumes:
- db_data:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: somewordpress
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
wordpress:
depends_on:
- db
image: wordpress:latest
ports:
- "8000:80"
restart: always
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
volumes:
db_data:
.ymlファイルがあるディレクトリで以下のコマンドを実行します。
docker-compose up -d
そうすると、compose.ymlをもとにコンテナを作成、起動します。実際にコンテナが起動していることを確認します。dockerfileがなくとも自動でイメージを引っ張ってきてコンテナを起動してくれます。
$ docker container ls
コンテナが起動している状態でhttp://localhost:8000にアクセスするとWordPressを使用することができます。
コンテナの停止と削除を行ってみましょう。
$ docker compose stop
[+] Stopping 2/2
✔ Container docker-wordpress-wordpress-1 Stopped 1.3s
✔ Container docker-wordpress-db-1 Stopped
$ docker compose down
[+] Running 3/3
✔ Container docker-wordpress-wordpress-1 Removed 0.0s
✔ Container docker-wordpress-db-1 Removed 0.0s
✔ Network docker-wordpress_default Removed
これで、作成したコンテナの削除が完了しました。(イメージは残っているため、イメージまで削除したい場合は--rmi allをオプションとして選択してください。)
Docker Hubとイメージの共有
これまでに散々紹介してきたDocker Hubの利用方法について最後に簡単に説明します。
Docker Hubの利用方法
Docker Hubにアクセスして、アカウントを作成しましょう。Googleアカウント、GitHubアカウントを使用してアカウントを作成することができます。
このようにDocker Hub上には様々なイメージが保存されています。興味のあるものを引っ張って遊んでみてください。
イメージのビルドと共有
Dockerfileで自分でオリジナルのイメージを作成した場合、そのイメージをDocker Hub上に共有することができます。
Docker Hub上にpushするためには、リポジトリの作成、Docker Hubへのログイン、イメージのタグ付け、Docker Hubへのプッシュのステップとなります。
まず、Docker Hub上でリポジトリの作成を行います。今回はubuntuというリポジトリを作成します。この時通常イメージ名をリポジトリ名とします。
次にこちらのコマンドでdockerにログインします。
docker login
ユーザー名とパスワードを要求されます。ログインが完了すると、「Login Succeeded」と表示されます。
次にpushしたいイメージに次のように名前を変更します。
docker tag <前のイメージ名>:タグ <ユーザー名>/<リポジトリの名>:タグ
docker tag ubuntu user_name/ubuntu:latest
pushする際にユーザー名とリポジトリの指定が必要となるため、イメージ名がわかりにくくならないようにリポジトリ名にはイメージ名を設定します(イメージ名と関係のない名前を設定すると何のイメージが入っているのかわかりにくくなる)。
最後にDocker Hubに名前を変更したイメージをプッシュします。
docker image push <ユーザー名>/<リポジトリ名>:タグ
docker image push user_name/ubuntu:latest
よりDockerの理解を深めるために、、、
Dockerチュートリアル
こちらのサイトではDockerを使用するためのチュートリアルが公開されています。チュートリアルを実際に行うことで、Dockerの理解をより深めましょう。
@Michinosukeさんが公開しているDockerチュートリアル和訳された記事も公開されているので参考にしてみてください。
書籍
今回できる限り盛り込んで説明を行いましたが、もちろんこの記事がDockerのすべてではありません。より体系的に学びたい場合は書籍から勉強することをおすすめします。
仕組みと使い方がわかる Docker&Kubernetesのきほんのきほん
おわりに
いかがでしたでしょうか。今回はdockerの開発環境の構築という点に焦点を当てて解説しました。1人でも多くの人の参考になればと思います。
弊社Nucoでは、他にも様々なお役立ち記事を公開しています。よかったら、Organizationのページも覗いてみてください。
また、Nucoでは一緒に働く仲間も募集しています!興味をお持ちいただける方は、こちらまで。