前回は、サボる方法(Docker Hubから公式イメージを持ってきてそれを使う方法)を紹介しました。
Docker Hubから取得したイメージを利用するのも良いのですが、だんだんカスタマイズしたくなってきます。
そんな、「もう少しこうしたい」と感じるようになったあなたのために、
今回のテーマは「自分でDockerfileからイメージを作ってみる」です。
ということで、今回は、
- Dockerfile作成
- 関連ファイルの作成
- イメージの作成(ビルド)
- イメージからコンテナを起動
- 動作確認
という手順で、例にならって、お馴染みnginxさんです。
Ubuntuにnginxを入れて「Welcome to nginx!」じゃないnginxを作ります。
今回覚えれるコマンド
カレントディレクトリのDockerfileをビルドする
% docker build -t ${REPO}:${TAG} .
ポートを指定してコンテナを起動する
% docker run -itd -p ${LOCAL_PORT}:${COTAINER_PORT} ${REPO}:${TAG}
できるもの
http://localhost
にアクセスすると、これが表示されるものを作ります。
デフォルトでは、以下のような画面になります。
ただ、nginxの部分変えただけじゃんという感想を抱くかもしれませんが、はいそうです笑
解説を含めた事前準備
前提条件
「nginx_dir
」というディレクトリにDockerfile、index.htmlというファイルを用意します。
Dockerfileをビルドする時はこのファイルがある前提でビルドします。
nginx_dir
L Dockerfile
L index.html
それでは、上記2つのファイルを作成していきます。
Dockerfileの作成
まずは、Dockerfileです。全然怖くありません。以下のようにやりたいことを淡々と書いていきます。
FROM ubuntu:20.04
RUN apt-get update
RUN apt-get install -y nginx
COPY ./index.html /var/www/html
EXPOSE 80
ENTRYPOINT ["nginx", "-g", "daemon off;"]
コマンドを順番に説明していきます。
1行目:FROM
FROMコマンドは「なんのイメージをベースを使いますか?そのイメージのバージョンは何ですか?」を記載してあげます。
これをベースイメージと言います。
今回は、Ubuntuの20.04のバージョンを使うぜという意味で「ubuntu:20.04
」宣言しています。
これ前回のDocker Hubからイメージ取得する回でも記載した{REPO}:{TAG}
の部分に相当します。
% docker pull ${REPO}:${TAG}
要は、内部でdocker pullをしている感じです。
他のベースイメージを利用したければこの部分を変更すれば良いわけです。
例えば、Dockerで使うOSのデファクトスタンダードでもあるAlpine Linuxをベースイメージにしたい場合は、alpine:3.15.3
と記載すれば良いわけです。
さらに、バージョン({TAG}
)もとりあえず最新版を持ってきてくれればいいというめんどくさがり屋さんは、xxxx:latest
と記載すればそのイメージの最新版を引っ張ってきてくれます。
※以下実施していくものはUbuntuベースで作ってます。Alpineベースでは動かない部分もありますので気をつけてください。
3, 4行目:RUN
RUNコマンドは「命令することがされた状態のイメージを作ってね」というコマンドになります。
今回はRUNコマンドが2つありますが、「apt-get update
」と「apt-get install -y nginx
」を実行された状態のイメージを作ってねという意味になります。
ここがオリジナルイメージを作る際にオリジナル要素を出せる部分です。
例えば、RUN mkdir xxx_dir
とすれば、xxx_dir
が作られた状態でイメージが作成されます。
6行目:COPY
COPYコマンドは「現実世界のファイルをコンテナ世界にコピーする」というコマンドになります。
今回はnginxの設定ファイルを一部置き換える目的で、ローカルにあるindex.html
ファイルをコンテナ世界の/var/www/html
にコピーしてねという意味になります。
なお、圧縮された状態のものを展開しつつ指定した場所へコピーするというADDというコマンドもありますが、これの使い分けや違いなどは各自調べてみてください。
参考:ADDとCOPY
8行目:EXPOSE
EXPOSEコマンドは「コンテナ世界としてはこのポートを開けて待ってます」というコマンドになります。
今回は80ポートをリッスンポートとして指定してます。
ただ、上記の通り「コンテナ世界”としては“」なのがポイントでもあるので注意してください(後述)。
ENTRYPOINT
ENTRYPOINTコマンドは「コンテナを起動したときにこれ実行した状態にして」というコマンドになります。
今回はnginxのプロセスを立ち上げた状態にしてという命令をしてます。
また、使い分け方が今いいちわからなくてもなんとなく動いちゃう可能性が高いCMDという似ているコマンドがありますが、「CMDは引数のために使うべき」と公式には記載されてますので違いは各自把握しておいてください。
ここでnginxと言うよりは、Dockerコンテナの特性を理解する上で重要なのがdaemon off
の部分です。daemonをoffにしてねとは、バックグラウンドで起動するをoffにしているという意味になります。
Dockerコンテナは「プロセスがフォアグラウンドで起動していないとコンテナは終了する」という特性があります。
なので、nginxをバックグラウンドで起動してもすぐに落ちてしまうのでフォアグラウンドで起動してねと明示してあげます。
わりと初心者が陥りやことなので覚えておきましょう。
index.htmlファイルの作成
次にindex.html
ファイルを作成していきます。と言っても、凝ったものは作るつもりがないので、以下のようなものを作りました。
<!DOCTYPE html>
<html>
<head>
<title>Welcome to DISCO MONSTER!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to DISCO MONSTER!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
はい、最初に完成形イメージとして表示しましたが、あまり芸が無いですが「Welcome to nginx!」を「Welcome to DISCO MONSTER!」にしました。
これで以上です。
実践
それでは、これら作成したファイルをもとにオリジナルイメージを作っていきましょう。
Dockerfileからイメージを作成する
% docker build -t ${REPO}:${TAG} .
最後の「.」を忘れないでください。
これは、カレントディレクトリのDockerfileをビルドするという意味です。
また、-t
でタグ名を指定してビルドするというオプションになります。
例:カレントディレクトリのDockerfileを「my-nginx:v1.0
」というリポジトリ名、タグ名でビルドする
% docker build -t my-nginx:v1.0 .
---
[+] Building 14.8s (9/9) FINISHED
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 198B 0.0s
=> [internal] load metadata for docker.io/library/ubuntu:20.04 1.8s
=> [1/4] FROM docker.io/library/ubuntu:20.04@sha256:cf31af331f38d1d7158470e095b132acd126a7180a54f263d386da88eb681d93 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 31B 0.0s
=> CACHED [2/4] RUN apt-get update 0.0s
=> [3/4] RUN apt-get install -y nginx 12.2s
=> [4/4] COPY ./index.html /var/www/html 0.0s
=> exporting to image 0.7s
=> => exporting layers 0.7s
=> => writing image sha256:a63eee4b051fd860b743477ee3a15ee263710da944540a153f58701aa9af1421 0.0s
=> => naming to docker.io/library/my-nginx:v1.0 0.0s
完了すると、FINISHED
と表示されます。
実際に、イメージを確認すると作られています。
% docker images
---
REPOSITORY TAG IMAGE ID CREATED SIZE
my-nginx v1.0 70f9143cc4ae 9 seconds ago 160MB
イメージからコンテナを立ち上げる
% docker run -itd -p ${LOCAL_PORT}:${COTAINER_PORT} ${REPO}:${TAG}
続いてコンテナdocker run
は前回の記事でも使っているのコマンドなの説明は省略します。
ここで、ポイントなのは-p
のオプションにより、「現実世界のポートとコンテナ世界のポートを変換する」ということです。
先ほど述べた、「コンテナ世界”としては“」ってやつです。
コンテナ世界としては80ポート開けたけど現実世界のどのポートと紐付けるかはコンテナ起動時に指定します。
例:現実世界の80ポートからコンテナ世界の80ポートへ変換する
% docker run -itd -p 80:80 my-nginx:v1.0
---
70f9143cc4ae0a996b76d6055da3315cb1241a44ad97b0e88e544d2dae4c4a63
これで立ち上げまで終わりました。準備完了です。
動作確認
実際に動作確認していきます。
まずは、dockerのプロセスを確認します。
% docker ps
---
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
70f9143cc4ae my-nginx:v1.0 "nginx -g 'daemon of…" 57 seconds ago Up 56 seconds 0.0.0.0:80->80/tcp serene_chatelet
うん、無事に起動してますね。
また、コンテナのPORT
の部分が0.0.0.0:80->80/tcp
と80ポートから80ポートへ変換されていることがわかります。
次にコンテナの中に入ってみましょう。
そして、/var/www/html
にコピーしたファイルがあるか確認しましょう。
% docker exec -it 70f9143cc4ae /bin/bash
---
root@70f9143cc4ae:~# ls -l /var/www/html/
total 8
-rw-r--r-- 1 root root 612 Apr 23 09:02 index.html
-rw-r--r-- 1 root root 612 Apr 24 02:16 index.nginx-debian.html
ちゃんとindex.html
が入ってますね。ちなみに、index.nginx-debian.html
がデフォルトで入っていたファイルです。
最後にブラウザ上でlocalhost
と入力してみましょう。
はい、上のような画面が出たらOKです。
以上、Dockerfileからオリジナルnginxのイメージを作る方法でした。
コメント