概要
Dockerのインストール、Image、Containerの基本的なところを整理してきましたが、今回はとうとうDockerfileを「自己整理」してみようと思います。
前提条件
- Windows10にDocker Desktopがインストールされている状態
Dockerfileとは?
Dockerfileとは、dockerの「build」コマンドを使う際に登場します。
今までの説明では、DockerHubからImageをpullしてきて、Containerを作り、そのContainerをいじるような流れでした。
「Containerは簡単に作れるが、ImageにはないものをContainerを作成するたびにインストールしたり設定したりするのは面倒なんだけど」
ということになります。
こうなると、「だったらImage自体を改変したい」ってなりますね。
例えば、前回の「httpd」ですが、Debian系、Alpine系しかないけど、Redhat系で作りたい。とか
使用するmoduleを最初から設定しておきたい。とか、、、、
Dockerfileは、pullしてきたImageを「ベース」として、自分用のImageを作るためのスクリプトファイルとなります。
Dockerfileの書式~buildまで
Dockerfileの書式リファレンス
まずは、Dockerfileの書式です。
やってみる(httpd)
それでは、まずは前回のApache httpdをDockerfileでやっていこうと思います。
その前に、ローカルのImageやContainerを全部消しておきます。(ここでは、もうゴミ扱い)
※Containerは停止させておいてください。
PS C:\> docker rm $(docker ps --filter status=exited -q)
PS C:\> docker rmi $(docker images -q)
これで、ImageとContainerは全て消えたはず。
PS C:\> docker ps -all
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
PS C:\> docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
PS C:\>
それでは、やっていきましょう。
まずは、Cドライブ直下に作業用のフォルダを作成します。
PS C:\> mkdir c:\docker_works\httpd
ディレクトリ: C:\docker_works
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 2022/06/20 01:37 httpd
PS C:\>
前回、httpdのImageをpullしてきて、Containerを起動した流れをおさらいします。
PS C:\> docker pull httpd:latest
PS C:\> docker run -d -p 8080:80 httpd
こんな感じでした。
続いて、メモ帳を開いて(私はサクラエディタを使ってますが)下記を「Dockerfile」という名前で作成したhttpdフォルダへ保存します。
FROM httpd:latest
続いて、「build」コマンドでImageを作成します。
PS C:\> cd .\docker_works\httpd\
PS C:\docker_works\httpd> docker build -t my_httpd .
[+] Building 8.1s (5/5) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 56B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/httpd:latest 3.5s
=> [1/1] FROM docker.io/library/httpd:latest@sha256:f899e432292e4ee92772d35e43b2e3dcf30042b1c6385d33f00a9300c69e 4.5s
=> => resolve docker.io/library/httpd:latest@sha256:f899e432292e4ee92772d35e43b2e3dcf30042b1c6385d33f00a9300c69e 0.0s
=> => sha256:f899e432292e4ee92772d35e43b2e3dcf30042b1c6385d33f00a9300c69ee729 1.86kB / 1.86kB 0.0s
=> => sha256:91b8f2e89503a8d3ee1aff392a1df086c7517b6448c29c24c68139c59831619c 1.37kB / 1.37kB 0.0s
=> => sha256:b260a49eebf92310bc8a6024591cb5c7846ca47ca30106a43d015c381bf87633 9.04kB / 9.04kB 0.0s
=> => sha256:42c077c10790d51b6f75c4eb895cbd4da37558f7215b39cbf64c46b288f89bda 31.38MB / 31.38MB 2.0s
=> => sha256:77a357ba66a85136c310c166c751585c8795e74205806bf582209dc6f98704af 175B / 175B 1.5s
=> => sha256:e9e2f87fc2cee5b3637255fd803d453cb13fa64fee5793272d27d10115741251 1.72MB / 1.72MB 1.4s
=> => sha256:de91965861a5e63599ec202f7bc8a09f0a6b74dd1c1a023816903bbc2cf58c83 300B / 300B 1.7s
=> => sha256:0b3c9bceb738771188edcce310e347b0799670cd65689d9908d543c4d16ff12b 23.97MB / 23.97MB 3.7s
=> => extracting sha256:42c077c10790d51b6f75c4eb895cbd4da37558f7215b39cbf64c46b288f89bda 1.0s
=> => extracting sha256:77a357ba66a85136c310c166c751585c8795e74205806bf582209dc6f98704af 0.0s
=> => extracting sha256:e9e2f87fc2cee5b3637255fd803d453cb13fa64fee5793272d27d10115741251 0.1s
=> => extracting sha256:0b3c9bceb738771188edcce310e347b0799670cd65689d9908d543c4d16ff12b 0.5s
=> => extracting sha256:de91965861a5e63599ec202f7bc8a09f0a6b74dd1c1a023816903bbc2cf58c83 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:882cc4d4cf13db875e044d8ea549ddaaa23924bf10a51082ff3049e2fd3b908f 0.0s
=> => naming to docker.io/library/my_httpd 0.0s
Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them
作成したImageを確認してみます。
PS C:\docker_works\httpd> docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
my_httpd latest 882cc4d4cf13 5 days ago 145MB
ふむ。
Containerを生成して実行してみます。
PS C:\docker_works\httpd> docker run -d -p 8080:80 my_httpd
e05c95d476879a0b3d53866840eee44ea4bf7234b68a32c9cee2390038b2d49b
PS C:\docker_works\httpd>
ふむ、まずはOK。
Containerを停止しておきます。
PS C:\docker_works\httpd> docker ps --all
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e05c95d47687 my_httpd "httpd-foreground" 2 minutes ago Up 2 minutes 0.0.0.0:8080->80/tcp unruffled_hamilton
PS C:\docker_works\httpd> docker stop e05c95d47687
e05c95d47687
PS C:\docker_works\httpd>
ステップアップ
体裁を整える
Dockerfileには、行頭に「#」を記載すればコメントアウトとして扱われます。
また、Imageの作成者(管理者)などの情報を書いたりできます。
せっかくDockerfileに色々用意されているので、使っていきましょう。
# 利用するTAGを指定
ARG VERSION=latest
# Hubからhttpdを取得
# https://hub.docker.com/_/httpd
FROM httpd:$VERSION
# 80番を公開する
EXPOSE 80
# 付属情報、LABELを増やすとレイヤーが増えるので1つにまとめておく
LABEL version="1.0" \
description="Modify sample httpd."
上書きして、build。一応、TAGに「latest」を付けておきました。
PS C:\docker_works\httpd> docker build -t my_httpd:latest .
[+] Building 2.4s (5/5) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 371B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/httpd:latest 2.3s
=> CACHED [1/1] FROM docker.io/library/httpd:latest@sha256:f899e432292e4ee92772d35e43b2e3dcf30042b1c6385d33f00a9 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:b1d643053f9664042cc2bdc33df6dc82c956ab377f9468b0f12fa37885ec3884 0.0s
=> => naming to docker.io/library/my_httpd:latest 0.0s
Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them
さて、ここから注意しておくことを書いておきます。
先ほど、「run」したContainerをなぜ「廃棄」せずに「停止」していたのか。
分かりやすいように、Docker Desktopの画面で見ましょう。
一見すると、なんともないですね。
でも、Containerを生成した際に使ったImageは、さっき更新しましたよね?
ということは、このContainerもImageの更新が自動的に反映されるのでしょうか・・・・?
答えは「No」です。
「my_httpd」のリンクをクリックすると
Image名のところが「<none>:<none>」になってますね。
更新されたImageに紐づいたContainerは「無い」ことになっていて、<none>に紐づくContainerがあることになっています。
実は、この状況はよくあることで、Docker Hubから取得したImageを使ってContainerを生成して使っていた時は良いのですが、何かのタイミングで
DockerHubから再度同じImageを取得して更新すると、使用中のContainerが紐づくImageがなくなってしまうようになります。
imagesコマンドで見るとこうなります。
PS C:\docker_works\httpd> docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> 882cc4d4cf13 5 days ago 145MB
my_httpd latest b1d643053f96 5 days ago 145MB
この個数で、何をやっていたかわかっている場合は良いのですが、いろいろやっていてImageがどんどん増えてきて、「不要なImageを消すか」と思い立って削除しようとすると、「使用中(Containerがある)」なので削除できない。と言われ、どのContainerがこのImageを使っているのか特定できねぇ・・・となって、Containerをバシバシ消していると必要なContainerまで消してしまった。みたいなこともありましたw。
「It works!」を変更する(上書き編)
動作確認で表示したページ「http://localhost:8080 」には「It works!」と表示されていました。
このテキストは、下記にindex.htmlとしておかれています。
# cd /usr/local/apache2/htdocs/
# ls -al
total 16
drwxr-xr-x 2 root root 4096 Jun 13 23:35 .
drwxr-xr-x 1 www-data www-data 4096 Jun 13 23:35 ..
-rw-r--r-- 1 504 staff 45 Jun 11 2007 index.html
# cat index.html
<html><body><h1>It works!</h1></body></html>
ということで、「index.html」を別途用意して、これをImageの作成時に上書きしてしまいましょう。
<html><body><h1>It MY works!</h1></body></html>
作成したindex.htmlは「C:\docker_works\httpd\cp_public_html」フォルダを作成して、その中に入れておきます。
それでは、再度Dockerfileを編集します。
# 利用するTAGを指定
ARG VERSION=latest
# Hubからhttpdを取得
# https://hub.docker.com/_/httpd
FROM httpd:$VERSION
# 【追加】自作のindex.htmlを配置する
COPY ./cp_public_html/index.html /usr/local/apache2/htdocs/
# 80番を公開する
EXPOSE 80
# 付属情報、LABELを増やすとレイヤーが増えるので1つにまとめておく
LABEL version="1.0" \
description="Modify sample httpd."
buildします。
PS C:\docker_works\httpd> docker build -t my_httpd:latest .
[+] Building 2.5s (7/7) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 472B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/httpd:latest 2.3s
=> [internal] load build context 0.0s
=> => transferring context: 137B 0.0s
=> CACHED [1/2] FROM docker.io/library/httpd:latest@sha256:f899e432292e4ee92772d35e43b2e3dcf30042b1c6385d33f00a9 0.0s
=> [2/2] COPY ./cp_public_html/index.html /usr/local/apache2/htdocs/ 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:9d7132f0f6218e79ac4f8cf8eb9b3f05c8b4c15cbf3cdf581f6b24aa3ecd6d1b 0.0s
=> => naming to docker.io/library/my_httpd:latest 0.0s
Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them
Containerを生成して起動します。
PS C:\docker_works\httpd> docker run -d -p 8080:80 my_httpd
f11efbec9b379308f04d333c3c9c6de61e3b1a525998b81fbcb8f963d9847261
「http://localhost:8080 」へアクセスして表示確認します。
きちんと上書きされましたね。
「It works!」を変更する(マウント編)
前述の上書き編は、Imageを作成する際の一度きりの変更や配置に使うものですが、Webページのように表示確認して、変更してと繰り返す場合は、ちょっと面倒ですね。
そこで、マウントしてしまう方法があります。
Docker Desktopの「Volumes」に表示される方法ですね。
それでは、まずはDockerfileのある場所に「public_html」フォルダを作成します。
このpublic_htmlフォルダ内に適当なindex.htmlを作成して配置します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Docker Test</title>
</head>
<body>
<h1>TEST</h1>
<h2>TEST</h2>
<h3>TEST</h3>
<h4>TEST</h4>
</body>
</html>
続いて、Containerを生成します。
(マウントは、Image作成ではできません。Containerを作成する際にローカル側のマウント元が実行環境で異なるからです)
PS C:\docker_works\httpd> docker run -d -p 8080:80 -v $pwd/public_html/:/usr/local/apache2/htdocs/ my_httpd
8501144b766c551b86e16b49d1de445e1a6d4e86e7a15c537fff1205d6741a06
Containerを起動したら、「http:localhost:8080」を開いてみます。
無事、マウントできているようです。
試しに、「docker inspect」してContainerの状態を確認します。
PS C:\docker_works\httpd> docker inspect 8501144b766c551b86e16b49d1de445e1a6d4e86e7a15c537fff1205d6741a06
[
{
"Id": "8501144b766c551b86e16b49d1de445e1a6d4e86e7a15c537fff1205d6741a06",
...
"HostConfig": {
"Binds": [
"C:\\docker_works\\httpd/public_html/:/usr/local/apache2/htdocs/" ←←←←
],
"ContainerIDFile": "",
...
"Mounts": [
{
"Type": "bind",
"Source": "/run/desktop/mnt/host/c/docker_works/httpd/public_html",←←←←
"Destination": "/usr/local/apache2/htdocs",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
...
Binds/Mountsの情報内に反映されてますね。
マウントしている状態なので、「public_html」フォルダ内にファイルを追加したり、index.htmlを変更すれば、即時に反映されることになります。
便利ですね。