この度開発環境でDockerを使う機会がありましたので、その際に学習したことについて簡単にまとめてみました。私自身も今回初めてDockerを体系的に触るということでしっかりとその全貌を理解する必要がありましたので、初心者目線でDockerについて書いていければと思います。
この度開発環境でDockerを使う機会がありましたので、その際に学習したことについて簡単にまとめてみました。私自身も今回初めてDockerを体系的に触るということでしっかりとその全貌を理解する必要がありましたので、初心者目線でDockerについて書いていければと思います。
こんにちは。
サーバーサイドエンジニアのゆうたです。
この度プロジェクトの開発環境でDockerを使う機会がありましたので、その際に学習したことについて簡単にまとめてみました。
私自身も今回初めてDockerを体系的に扱うということで、しっかりとその全貌を理解する必要がありましたので、キャッチアップする必要がありました。
今回はそんな学習過程で得た知識について初心者目線で書いていければと思います!
今回ブログ記事を書くにあたっての私の経験値・レベル感については以下の通りです。
以上です。
上記のレベル感に近ければ近いほど、私と同じ目線でDockerについて学ぶことができると思いますので、ぜひ一緒にがんばりましょう! それ以外の方でもDockerについて知るきっかけになってもらえれば良いかなと思っています。
それではよろしくお願いします!!
また、以前仮想環境(LAMP環境)の構築について執筆した記事がありますので、興味があればぜひこちらも合わせてご覧いただければと思います。
はじめてのLAMP環境構築 〜 LAMP環境とは?|Engineering|EMoshU Blog|株式会社EMoshU
EMoshU Blog|今回のブログでは、弊社EMoshUのコーポレートサイトの開発のために、LAMP環境を構築したことをまとめました。
前回のVagrant仮想環境の構築に引き続き、今回Dockerでの環境構築についてのこの記事を読んでいただくことで、今後の開発環境の選択肢も広がりますし、さらにより環境周りの仕組みについても理解が深まると思います。
さらに、後半部分ではハンズオン形式で実際に手を動かしてDockerに触れていきますので、ぜひ一緒にやってみてください!
それでは最後までご覧ください!!
まずはDockerの概要について簡単に解説していきたいと思います。
Dockerとは、コンテナ型の仮想化プラットフォームになります。わかりやすく言い換えると、仮想環境を構築するためのツールです。
WindowsやMac、Linuxなどのホストマシン上に「コンテナ」と呼ばれる仮想環境を構築し、その中でミドルウェアやアプリケーションを動かすことができます。
次章以降で、コンテナという言葉やDockerを使うメリットについては詳しく解説していきます。まずは「Dockerは仮想環境を構築するためのツール」であると思っていただければ十分です。
ではこれからコンテナについて解説していきたいと思いますが、まずは「仮想化」と「コンテナ」の違い、そしてそれぞれの特徴について理解していただけたらと思います。
ここが理解できるとそれぞれでの環境がどのようにPC上で動いているかが分かるようになり、よりDockerが扱いやすくなるでしょう。
「仮想化」とは、ホストマシン上で別のゲストマシンを起動させる仕組み。つまり、現在動いているホストマシンのOS(ホストOS)の上で、仮想化ソフトウェアを用いて複数の仮想マシンを起動させることができます。複数の仮想マシンそれぞれでOSやミドルウェア(バイナリ・ライブラリ)、アプリケーションを持つことができます。
しかし仮想化では、OSの上にもう一つのOSが起動していることになるので、より多くのリソース(CPUやメモリ)を消費することになります。
それでは仮想化を表す図を作成してみましたので、こちらでより具体的なイメージを掴んでもらえたらと思います。
それぞれの階層の詳細は以下の図になります。上図と照らし合わせてご覧ください。
一方の「コンテナ」は、Dockerエンジン上で動いている仮想環境のことを指します。
コンテナは、ホストOSのカーネル(OSの中核となる部分)を利用しており、各コンテナがこのカーネルを共有することで、ホストマシンのリソース(CPUやメモリ)の消費を軽減しています。そのため、仮想化よりも軽量で高速に動作すると言われています。
コンテナについても簡単な図を作成したので、ご覧ください。
ここで、仮想化とコンテナによるアプリケーションの起動までを簡単に比較してみたいと思います。
例えば、仮想化を用いた環境でApacheを起動するとします。この場合、まずVirtualBoxやVM Wareなどの仮想化ソフトウェア上にあるゲストOSを起動し、完了後にApacheのプロセスが動き出し、初めてApacheが起動するようになります。途中にゲストOSの起動を待たなければならない分、Apacheの起動までには時間がかかります。
一方でコンテナであれば、仮想マシンを立ち上げるために必要だった仮想化ソフトウェアとゲストOSが必要ありません。そのため、仮想化よりも高速にアプリケーションの起動まで辿り着くことができます。
いかがでしょうか? ここまでざっくりではありますが、「仮想化」と「コンテナ」の違いについて簡単に説明してきました。少しは理解できたのではないでしょうか?
では、以降の章からはDockerのより詳細な部分についての解説をしていきたいと思います!
初心者がDockerを扱ううえで最低限絶対に覚えておくべき用語がいくつかありますので、簡単に解説をつけながら紹介していきます。
名称 | 説明 |
---|---|
Docker Engine | イメージの作成やコンテナの起動などを行うDockerの核となる部分。 Linuxのカーネルを使ってメインの処理を行う。 |
コンテナ | Docker上で動作するアプリケーションの単位。 サーバーの中で隔離された空間を作り、その中にアプリケーションを入れて動作させる。 |
Docker Image(イメージ) | コンテナを作成するための依存関係や情報を含むデータ。 コンテナはこのイメージを元にして作成される。 |
Dockerfile | イメージをビルドするための手順が記載されたファイル。 オリジナルのイメージを作成したい場合は、ファイルを用意する必要がある。 |
Docker Compose | 複数のコンテナで構成されるアプリケーションにおいて、イメージのビルドや各種コンテナの操作(起動や停止など)をより簡単に行えるツール。 docker-compose.ymlというファイルに、複数コンテナを起動させるための設定を記述します。 |
今回Docker Composeについてはほとんど解説しませんが、複数コンテナを起動させて連携させるようなアプリケーションでは必須のツールなので、興味を持たれたら調べてみるといいかもしれません。
ここではDockerを操作する上で必要なコマンドについて、簡単な解説とともに紹介していきます。
これから紹介するコマンドは本当によく使うので、今の時点ではこういったコマンドがあるんだな程度に覚えてもらって大丈夫です。
実際にDockerを扱うようになると何度も使うので自然と覚えることができますので!
紹介するコマンド一覧
Dockerコンテナ1つを起動するコマンド
→ イメージがない場合は、Docker Hubから自動で取得する
Docker Hubとは、ユーザーが作成したコンテナをアップロードして公開・共有できるサービスで、オープンに公開されているものは自由にダウンロードして使うことができます。
# コマンド記述例
$ docker run コンテナ指定
# 今回はhello-worldのイメージを用意していないため、Docker Hubから取得する
$ docker run hello-world
docker runコマンドでよく使うオプション
オプション | 説明 |
---|---|
--name | コンテナに任意の名前をつける |
--rm | プロセスが終了したらコンテナを削除する |
--volume | コンテナにホストのディレクトリをマウントする |
-it | コンテナの中に入る(インタラクティブシェルモード) |
-p | コンテナにアクセスする、ポートの開放をする |
--env | 環境変数(DBのパスワードなど)を渡す |
# コンテナに任意の名前をつけて立ち上げる
$ docker run --name hello-my-world hello-world
# コンテナが停止した後、削除する
$ docker run --name rmtest --rm hello-world
# bashを使用してcentosのコンテナに入って操作をする
# 実行するとプロンプトがDocker IDに変化する
$ docker run -it --name mycentos centos:8 /bin/bash
起動中のコンテナを表示するコマンド
デフォルトでは停止中のコンテナは表示されないので、停止中のコンテナも表示させたい場合は-aオプションをつける
# コンテナが動いていない状態
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# -aオプションをつけて実行する(停止中コンテナも表示される)
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a5f80f2d696c hello-world "/hello" 8 minutes ago Exited (0) 8 minutes ago crazy_leavitt
一つのコンテナを操作する(開始・停止・再起動)
いずれも削除はしないので、コンテナは残る
コンテナ指定 → コンテナID or コンテナ名
つまりコンテナ1つを指定する値があればよい
# コマンド記述例
$ docker start コンテナ指定
$ docker stop コンテナ指定
$ docker restart コンテナ指定
# mycentosを起動する
$ docker start mycentos
# mycentosを停止する(Docker IDで指定)
$ docker stop e1689efe6a26
# mycentosを再起動する
$ docker restart mycentos
コンテナに入るとは?
コンテナ内のコマンドライン(bashやzsh)にアクセスすること
→ コマンドライン経由でコンテナを操作できるようになる
起動中のコンテナ内でコマンドを実行する
起動中のコンテナに入らずにコマンドを実行する
-itオプションを付けることでコンテナに入ることができる
# コマンド記述例
$ docker exec コンテナ指定 コマンド
# mycentosコンテナに入る
$ docker exec -it mycentos /bin/bash
# CentOSのバージョンを確かめる
[root@e1689efe6a26 /]$ cat /etc/redhat-release
CentOS Linux release 8.2.2004 (Core)
# コンテナに入らずにCentOSのバージョンを確かめる
$ docker exec mycentos cat /etc/redhat-release
CentOS Linux release 8.2.2004 (Core)
停止中のコンテナを削除する
基本的には停止中のコンテナしか削除することができないが、-fオプションで起動中コンテナも強制削除になる(-fオプションは強制的なので、おすすめしません)
→ コンテナのデータも消えるので注意が必要です!
# コマンド記述例
$ docker rm コンテナ指定
# ID指定でコンテナを削除する
$ docker rm a5f80f2d696c
# 起動中のコンテナを削除する(-fオプション)
$ docker start mycentos
$ docker rm -f mycentos
ローカルにあるDockerイメージを全て表示する
意外とDockerイメージは容量が大きい
→ 定期的に確認するのがおすすめ
また、コンテナと同じくDockerイメージも一意なIDを持っている
# Dockerイメージの一覧を表示
$ docker images
Dockerイメージを削除する
起動中のコンテナのイメージは削除できない
→ Dockerイメージは依存関係があるため、ベースイメージは削除できない
# コマンド記述例
$ docker rmi イメージ指定
# 立ち上げているコンテナは一度削除してからそのイメージも削除する
$ docker rm hello-my-world
$ docker rmi bf756fb1ae65
イメージが<none>になる条件は、新しいイメージが既存のタグを再利用したときになる。 古い方のイメージがタグを剥奪される。
# <none>イメージを一括削除する
$ docker image prune
Dockerfileからイメージを作成する
# コマンド記述例
$ docker build Dockerfileパス
# シンプルなDockerfileを作成する
$ mkdir test
$ touch test/Dockerfile
# Dockerfileの中身を確認する
$ cat test/Dockerfile
FROM centos:7
RUN yum update -y
# ビルドしてイメージを作成する
$ docker build test
# 作成されたイメージを確認する
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> e112239fc121 31 seconds ago 452MB
コンテナとホストマシンでファイルのやりとりを行うコピーコマンド
ログファイルや設定ファイルの取り出しなどで使用することができる
# コマンド記述例
# ホスト → コンテナへのコピー
$ docker cp ホストファイルのパス コンテナ指定:コンテナのパス
# コンテナ → ホストへのコピー
# コンテナからホストへのコピー実行においても、コンテナ内からではなく、コンテナの外から実行する
$ docker cp コンテナ指定:コンテナファイルのパス ホストのパス
# mycentosを立ち上げる
$ docker run -it --name mycentos centos:8 /bin/bash
# mycentosを起動する
$ docker start mycentos
# サンプルファイルをコンテナにコピーする
$ docker cp ~/Developer/sample.txt mycentos:/opt
# コンテナに入ってコピーを確認する
$ docker exec -it mycentos /bin/bash
[root@b1234e42cf6f /]$ cat /opt/sample.txt
sample txt file for test docker
# コンテナ → ホストへのコピー用ファイル作成
[root@b1234e42cf6f /]$ vi /opt/container.txt
# コンテナ → ホストへのコピーを行う
$ docker cp mycentos:/opt/container.txt ~/Developer/docker
Dockerコンテナのログ出力する
→ -fオプションでリアルタイムログを出力する
# コマンド記述例
$ docker logs コンテナ指定
# コンテナが起動している状態でログを確認する(ターミナルの別タブで確認)
# コンテナ名 or コンテナIDを指定する
$ docker logs mycentos
# リアルタイムログを確認する
# ctrl + Cで抜ける
$ docker logs -f mycentos
長々となってしまいましたが、ここまでじっくりと基本的なDockerコマンドについて見てきました。
この章のはじめにもお伝えしたように、一回ですべて覚えなくて当然大丈夫です。これから何度もDockerに触れていくうちにここで紹介したコマンドは絶対に登場するので、実際に使っていくうちに覚えられるようになります!
それでは実際にDockerに触れる前にもう一つ、Dockerfileの中で使用する主要なコマンドを見てみましょう!
頻繁に使用する以下のコマンドのみ簡単に紹介していきます。
どちらもLinuxコマンドを実行する
→ しかし、実行タイミングが異なる
RUN:Dockerfile → イメージ(一度だけ実行される)
CMD:イメージ → コンテナ(イメージ作成後に実行される)
コマンド記述例
RUN apt-get install -y nginx
# ダブルクォーテーションで囲う
CMD ["nginx", "-g", "daemon off;"]
Docerfile
FROM ubuntu:20.04
RUN apt-get update -y && \
apt-get install -y nginx
CMD ["nginx", "-g", "daemon off;"]
Dockerコマンド実行例
# -tオプションでイメージ名をつける
$ docker build -t dockerfile-run-nginx run/
# イメージからコンテナを立ち上げる
# -dでバックグラウンド実行
$ docker run -d -p 8081:80 --name docerfile-run-nginx dockerfile-run-nginx
コンテナが立ち上がったことを確認する http://localhost:8081
どちらもファイルをイメージに追加するコマンド
→ ADDは機能が豊富にあり、ネット経由からでもファイルを追加することができる(圧縮ファイルも追加することができる)
基本はローカルからの追加なので、COPYを推奨
COPYの使いどころ
コマンド記述例
COPY ホストのファイル コンテナのパス
Dockerfile
FROM ubuntu:20.04
# RUNコマンドでインストールされるnginxのバージョンでは/var/www/htmlがドキュメントルートになる
RUN apt-get update -y && \
apt-get install -y nginx
COPY index.html /var/www/html
CMD ["nginx", "-g", "daemon off;"]
Dockerコマンド実行例
# ビルドを行う
$ docker build -t dockerfile-copy-nginx copy/
# コンテナを起動する
$ docker run -d -p 8082:80 --name dockerfile-copy-nginx dockerfile-copy-nginx
コンテナが立ち上がったことを確認する http://localhost:8082
環境変数を設定する
ただし、直接書き込みでの固定値になってしまう(ユーザーによって変えられない)
コマンド記述例
# DB_USERを設定
ENV DB_USER yuta
Dockerfile
FROM ubuntu: 20.04
RUN apt-get update -y && \
apt-get install -y nginx
ENV TESTENV="yuta"
# アプリの環境とは、開発環境、テスト環境、本番環境など
ENV APP_ENV="production"
CMD ["nginx", "-g", "daemon off;"]
Dockerコマンド実行例
# ビルドを行う
$ docker build -t dockerfile-env-nginx env/
# コンテナを起動する
$ docker run -d -p 8083:80 --name dockerfile-env-nginx dockerfile-env-nginx
docker inspectで環境設定を確認する
$ docker inspect dockerfile-env-nginx
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"TESTENV=yuta",
"APP_ENV=production"
]
お疲れ様です! ここまで長々とDockerについての解説を行ってきましたが、最後は少しだけDockerに入門してみましょう。
ここでは「JSON Server」というAPIモックツールを使用し、ごく簡単なAPIサーバーをコンテナとして立て、簡単なリクエストを送って実際にAPIが動いているかを見てみたいと思います!
JSON Serverとは、JSONファイルを元にして簡単にWebAPIモックアップを作成できるnpmのパッケージです。導入も使い方も非常に簡単なので、今回扱ってみようと思いました。
私が普段使用しているのがMacなので今回はMac向けの解説になってしまいますが、そこはご了承ください。
以下の手順で進めていきます!
さぁ、やっていきましょう!
ではまず「Docker for Mac」をインストールしてみましょう。以下のリンクからダウンロードページへアクセスすることができます。
以下のページから自分のPCに合ったバージョンでダウンロードします。私はMacのIntelチップなので、選択してダウンロードを行います。
その後は他のソフトウェアと同じく、インストールまでを行います。
インストール完了したら、Docker for Macを起動してみましょう!
画像のように上部のツールバーが「Docker Desktop is running」と緑色の丸と一緒に表示されていれば、Docker Desktopが正常に起動していることがわかります。Dockerを扱う時はこの状態で操作を行います。
ここではコンテナを立ち上げるのに必要なフォルダやファイルを準備しましょう。
Dockerコンテナを作成するにはこのパートが一番大事な部分になります。
Dockerfileやdocker-compose.ymlファイルにミスがあると、正常にコンテナの立ち上げができなくなりますので、よくよく注意しながら作成しましょう。
まずプロジェクトフォルダを作成します。作成場所はどこでも大丈夫です!
最終的には以下のプロジェクト構成になります!
api-test
├── docker-compose.yml
└── json-server
├── Dockerfile
└── data.json
ターミナル上でコマンドを実行します。
# プロジェクトフォルダの作成と移動
$ mkdir api-test
$ cd api-test
# docker-compose.ymlの作成
$ touch docker-compose.yml
続いてdocker-compose.ymlの内容を記述します。
Docker Composeに関してはDocker用語の章でほんの少ししか触れていませんので、初めて見る記述もあるかと思いますが、今回は以下と同じ記述をしてみてください。
# docker-compose.yml
version: "3"
services:
json-server:
build: ./json-server
container_name: json-test-server
ports:
- "3000:3000"
volumes:
- ./json-server/data.json:/data/data.json
command: json-server --watch data.json --host 0.0.0.0
さらにapi-testの中にもう一つフォルダを作成し、その中でDockerfileとdata.jsonを作成します。
# プロジェクトフォルダの作成と移動
$ mkdir json-server
$ cd json-server
$ 各ファイルの作成
$ touch Dockerfile
$ touch data.json
Dockerfileの内容を記述します。先程紹介したコマンドも実際に使っています。
# Dockerfile
# ベースとなるイメージを指定
FROM node:latest
# JSON Serverをインストール
RUN npm install -g json-server
# 作業ディレクトリを/dataにする
WORKDIR /data
# 公開ポート番号
EXPOSE 3000
最後にdata.jsonを記述します。
私はMLBが好きなので、今回はMLBのチームをデータとして持たせたいと思います。
# data.json
{
"posts": [
{
"id": 1,
"team": "New York Yankees"
},
{
"id": 2,
"team": "Boston Red Sox"
}
]
}
以上でファイルの作成は完了です。続いてコンテナの立ち上げを行ってみましょう。
それではいよいよコンテナを立ち上げてみましょう! 以下のコマンドを実行します。
# 実行場所はapi-testディレクトリ内に移動する(docker-compose.ymlと同じ階層で立ち上げるため)
$ cd ..
# コンテナをビルドして立ち上げる
$ docker compose up -d --build
上記のコマンドでコンテナのビルド〜立ち上げがスタートします。初回は少し時間かかると思います。
立ち上げが完了したら以下のURLにアクセスして、コンテナが起動しているか、JSON Serverが動いているかを確認しましょう。
JSON Serverのページが表示されればOKです。
ではここからはcurlコマンドを使ってリクエストを送信し、立ち上げたコンテナ・JSON Serverからのレスポンスを確認してみましょう!
ターミナルでそれぞれcurlコマンドを実行してみます。
GET
# curlコマンドを実行する
$ curl -X GET http://localhost:3000/posts
# レスポンス
[
{
"id": 1,
"team": "New York Yankees"
},
{
"id": 2,
"team": "Boston Red Sox"
}
]
はじめにdata.jsonに記述した内容が返ってきていることがわかります。
POST
# curlコマンドを実行する
$ curl -X POST -H "Content-Type: application/json" -d '{"id":3,"team":"Los Angeles Angels"}' http://localhost:3000/posts
{
"id": 3,
"team": "Los Angeles Angels"
}
# GETで確認する
curl -X GET http://localhost:3000/posts
[
{
"id": 1,
"team": "New York Yankees"
},
{
"id": 2,
"team": "Boston Red Sox"
},
{
"id": 3,
"team": "Los Angeles Angels"
}
]
PUT
# curlコマンドを実行する
$ curl -X PUT -H "Content-Type: application/json" -d '{"id":3,"team":"Toronto Blue Jays"}' http://localhost:3000/posts/3
{
"id": 3,
"team": "Toronto Blue Jays"
}
# GETで確認する
$ curl -X GET http://localhost:3000/posts
[
{
"id": 1,
"team": "New York Yankees"
},
{
"id": 2,
"team": "Boston Red Sox"
},
{
"id": 3,
"team": "Toronto Blue Jays"
}
]
DELETE
# curlコマンドを実行する
$ curl -X DELETE http://localhost:3000/posts/3
{}
# GETで確認する
$ curl -X GET http://localhost:3000/posts
[
{
"id": 1,
"team": "New York Yankees"
},
{
"id": 2,
"team": "Boston Red Sox"
}
]
これで、JSON Serverのコンテナに対してGET、POST、PUT、DELETEのリクエストを送信し、実際にレスポンスが確認できました。
よって、コンテナとJSON Serverが正常に動いたことがわかりました。
いかがだったでしょうか? 規模の大きいアプリーションになるとコンテナがいくつもあって、それが相互に連携しているのでより複雑になりますが、今回は"実際にDockerを動かす"ということで簡単に扱えるJSON Serverを導入して動作確認をしてみました。
ここまで読んでいただきありがとうございました。
今回はDocker環境構築について学習した内容をまとめてみました。
初めはDockerという言葉もイマイチわかっていませんでしたが、一つ一つ調べていくうちに徐々にどのようなものかが少しずつわかってきました。
前回私はVagrant環境構築に関する記事を執筆させていただきましたが、仮想化ソフトウェア(VirtualBox)を使用した経験があったため、コンテナとの違いについては理解しやすいところもありました。
また、今回は単体のコンテナを起動させて動作を確認しましたが、Docker Composeを利用するといくつものコンテナを同時に立ち上げ、さらに相互に連携させることもできます。
Docker Composeについては気になった方はぜひ調べてみてください! どちらにせよ今回扱った内容は基礎的な部分ですので、Dockerを触るには欠かせない知識になってきます。
もっと学習を重ねていき、今後はより複雑な開発環境にもチャレンジしていけたらと思っています。
最後になりますが、EMoshUでは一緒に開発できる仲間をいつでも募集しております。
EMoshUブログを読んでご興味を持たれましたら、是非下記の募集要項をご覧ください。カジュアル面談なども実施しております!
はじめてのLAMP環境構築 〜 LAMP環境とは?|Engineering|EMoshU Blog|株式会社EMoshU
EMoshU Blog|今回のブログでは、弊社EMoshUのコーポレートサイトの開発のために、LAMP環境を構築したことをまとめました。