Docker超入門ハンズオン〜Build/Ship/Runをコンプリートせよ〜


最近会社でDocker講座+ハンズオンを開催したので、内容をここで共有します。
講座のスライドはSpeakerDeckに挙げていますので良かったらご覧ください。
Web開発における開発環境構築の歴史と変遷〜原始時代から現代(Docker)まで〜

本記事ではハンズオンの内容を記載します。


■ハンズオンについて
ゴール(目的):
Dockerのスローガンである「Build/Ship/Run」を経験して基本的な使い方を理解しよう

Step1,2ではDockerfile→イメージ→コンテナの作成を行います。(Build,Run)
Step3ではDockerHubにオリジナルのイメージを登録し、それをベースイメージとしたDockefileから新しいイメージ作成〜コンテナを起動します。 (Ship)

対象者:
Docker初心者(中級者以上でも良い復習になるかも)

前提条件:
・DockerHubアカウントがあること
・Docker for Windows/Macをインストール済でdockerコマンドを叩けること

Docker for Windowsのインストール
https://ops.jig-saw.com/techblog/docker-for-windows-install/

Docker for Macのインストール
https://qiita.com/kurkuru/items/127fa99ef5b2f0288b81


それではハンズオンスタート!

Step1. 「Hello, Docker World」

Dockerfileを作ってイメージをビルドしてみよう

手始めにDockerfileを格納するためのディレクトリを作ります
※基本的にMacでのコマンドとなります。Windowsは特に注意する部分だけ補足説明を行いますので悪しからず。

例.

mkdir ~/workspace/docker/sample
cd sample 

作成したディレクトリ内でDockerfileを作成
内容は以下をコピペしてください

# 利用するベースイメージの指定
FROM ubuntu:18.04

# コマンド
CMD echo 'Hello docker world!'

作成したDockerfileを基にイメージをビルド!

docker build ./ -t sample

イメージが出来たかを確認

$ docker images | grep sample
sample                latest              50bca976fdec        1 minute ago          64.2MB

イメージからコンテナを起動してみよう

コンテナよ、起動せよ(以下コマンド実行)

$ docker run sample
Hello docker world!

起動時にコンテナ内部に接続してみる

$ docker run -it sample /bin/bash
root@ecaf5cd9e646:/#

runコマンドで-itオプションをつけてbash を起動するように指定すると、ターミナルでコンテナ内部を操作できます。

オプションの詳細については以下をご参考に
【図解】docker runのオプションいろいろ #マンガでわかるDocker 番外編

なのでコンテナに接続してからじゃなくても、直接起動と同時にコマンドを実行可能。

$ docker run -it sample ls
bin   dev  home  lib64  mnt  proc  run   srv  tmp  var
boot  etc  lib   media  opt  root  sbin  sys  usr

コンテナの起動について

これまでの操作で実はrunした分コンテナは作成されているのにお気づきでしょうか?

試しにコンテナリストを表示する docker ps コマンド を実行

$ docker ps -a | grep sample
804a41759e16        sample              "ls"                     22 seconds ago      Exited (0) 21 seconds ago                            elastic_mayer
1a8b5f7bee72        sample              "/bin/bash"              2 minutes ago       Exited (0) 24 seconds ago                            cocky_darwin
a98cd2ab3cfa        sample              "/bin/sh -c 'echo 'H…"   3 minutes ago       Exited (0) 3 minutes ago                             laughing_darwin

デフォルトでは起動しているコンテナだけ表示するが、-a オプションをつけると起動していないコンテナも含めた全てのコンテナを表示

要らないコンテナ・イメージを削除

docker rm コンテナID|コンテナ名で指定したコンテナを削除できますが、めんどくさいので一括で削除しちゃいましょう

まずはこのコマンドで先程psコマンドとコンテナID群が一致している事を確認
docker ps -a -f "ancestor=sample" -q
-f: フィルターオプション。ancestor=***で指定したイメージ名から作成されたコンテナを絞り込むことができる
-q: コンテナIDだけ表示

こいつをrmコマンドで使うと一括で削除できる

docker rm `docker ps -a -f "ancestor=sample" -q`

イメージも削除

docker rmi sample

Step2. Nginxコンテナを使ってみる

Nginxのコンテナを起動してホストPCからアクセスしてみよう
※今度はDockerfileを書く必要がなく公式イメージから直接コンテナを起動します

docker run -d --name nginx1 -p 8080:80 nginx

-d: デタッチドモード。バッググラウンドで実行
-p: ポートフォワーディング [ホスト側ポート番号]:[コンテナ側ポート番号]

localhost:8080にアクセスしてnginxデフォルトページを確認

わずか数十秒でnginxの環境が出来上がった。これこそがDockerの手軽さ!

しかしここで一つの重要な疑問
「あれ?さっきのHello worldと違ってNginxコンテナは動き続けてる。これって何で?」
冒頭で共有したスライドでも説明してますが、コンテナが起動し続けるには何かしらのプロセスがフォアグラウンドで動く必要があります

端末からの入力を受け付ける状態になっているプロセスはフォアグラウンドプロセスといい、そうでない他の全てのプロセスはバックグラウンドプロセスです。


フォアグラウンドプロセスの例:topコマンドを叩いたらプロセスがフォアグラウンドで起動します。
Ctrl + Cを入力することによってプロセスにSIGINTを通知され、プロセスが終了します。

Nginxはデフォルトはデーモンで動きますが、実はNginxコンテナはフォアグラウンドで動くようDockerfileで設定しています。
NginxのDockerfileを見てみると、最後に CMD ["nginx", "-g", "daemon off;"]の行がありますね。

このおかげでコンテナが起動し続けることが出来るわけです。

ハンズオンに戻り、今度はNginxコンテナに接続します
(runではなくexecで実行)

docker exec -it nginx1 /bin/bash

コンテナ内でNginxバージョンを確認

root@4ee30cf1b12c:/# nginx -v
nginx version: nginx/1.17.8

bash立ち上げなくても普通にコマンド実行もできる

docker exec -it nginx1 ls

Step3. DockerHubを使ってみよう

DockerHubへイメージを登録

まずはStep1で使用したHelloWorldのDockerfileを基に登録用のイメージを作成
さっきはdocker build ./ -t sample で作りましたが、DockerHubに登録する為には{DockerHubアカウント名}/{イメージ名}にする必要があります

アカウント名はログインする時のユーザー名となります。
DockerHubのプロフィールページから確認もできます。

DockerHubのページから「My Profile」をクリックするとプロフィールページに飛びます。

自分の場合、endamがアカウント名になります。

{DockerHubアカウント名}/sampleでイメージを作成しましょう。

docker build ./ -t endam/sample

作成したイメージを確認

$ docker images | grep sample
endam/sample          latest              50bca976fdec        3 days ago          64.2MB

コマンドラインからDockerHubにログイン
DockerHubに画面上からログインする時のユーザー名(アカウント名)・パスワードと同じです。

$ docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: xxxxxxxxxxxxxxx
Password:
Login Succeeded

既にログインしている人は「Login Succeeded」が表示されればOKです。

$ docker login
Authenticating with existing credentials...
Login Succeeded

イメージをDockerHubにアップローード!

docker push endam/sample:latest

DockerHubでイメージが登録されていることを確認

DockerHubに登録したイメージを基に新しくコンテナを作る

新しいDockerfileを作るのでHelloWorldのDockerfileをコピー&退避させてあげましょう

cp Dockerfile Dockerfile.bak

Dockerfileを修正

# 利用するベースイメージの指定
FROM endam/sample

# ディレクトリ作成
RUN mkdir sample

Dockerfileからイメージをビルド

docker build ./ -t sample2

イメージからコンテナを起動すると「Hello docker world!」が出力されます
(ベースイメージがちゃんと自分が作ったオリジナルイメージだということが分かる!)

$ docker run sample2
Hello docker world!

ちなみに新しいDockerfileの内容であるsampleディレクトリの作成が行われていることも確認

$ docker run -it sample2 ls
bin   dev  home  lib64  mnt  proc  run     sbin  sys  usr
boot  etc  lib   media  opt  root  sample  srv   tmp  var

ホストPCのディレクトリをコンテナにマウントしてみる

今回はコンテナ起動時にホストPCのディレクトリをコンテナにマウントするのでその準備をする

Dockerfileがあるディレクトリ内でsrcディレクトリを作成。

mkdir src

srcディレクトリ内で適当に新しいファイルを作成する。(マウント確認用)
↓はMacの場合なのでtouchコマンドで空ファイルを作成しています。
Windowsの人は【Windows】空のファイルを作成するの記事を参考にしてください。

cd src
touch a.txt

コンテナ起動時にマウントの指定

docker run -v /Users/***/workspace/docker/sample/src:/app --name sample2 -it sample2 /bin/bash

-vで指定するホストとコンテナのパスは絶対パスなので要注意

docker run -v [ホストディレクトリの絶対パス]:[コンテナの絶対パス] [イメージ名] [コマンド]

特にWindowsの人はここでハマりやすいです。
C:¥**ではなく/C/***という記述になります。

例:/C/Users/{ユーザディレクトリ}/Documents/workspace/docker/sample/src:/app

コンテナに接続後はappディレクトリ内に事前準備で作ったファイルが置かれていることを確認しましょう。

root@da7bcd4255d1:/# ls app
a.txt

ハンズオンComplete!

これでDockerのスローガンであるBuild/Ship/Runを全て体験完了しました!

もしやってみて詰まったり、疑問がある方、「勉強になったので***のハンズオン内容も載せて欲しい」という方は気軽にコメントをください。お待ちしています。