Help us understand the problem. What is going on with this article?

Dockerを体験してみるハンズオン Part3

More than 3 years have passed since last update.

前回までのあらすじ

今回はDockerイメージを実際に作成してリポジトリに登録してみます。

ここで使用しているソースコードはこちらに格納してあります。
https://github.com/NewGyu/docker-demo
readme.mdにもある程度のことを書いてあるので参考にしてください。

ビルドできる環境を作る

https://github.com/NewGyu/docker-demo をビルドするには

  • JDK...tomcatにデプロイするwarファイルを作るため
    JREではなく、javacを含むJDKが必要になります(コンパイルするので)
  • git...上記のソースコードを取得するため

が必要です。

$ sudo yum install java-1.8.0-openjdk-devel git

勘違いしてほしくないのはこれらはDockerコンテナを動かす上では必要ありません。あくまで私が用意したサンプルをコンパイル・ビルドするために必要だということです。

本来は以下のようにビルド環境と実行環境は別々になるのですが、

今回のハンズオンでは一つのインスタンスでまとめてやってしまいます。

ビルドしてみよう

ソースコードを取得

普通にgithubからソースコードをcloneで取得してください。

$ git clone https://github.com/NewGyu/docker-demo.git

こんなディレクトリ構成です。

docker-demo/
├── app                ...下記のinfraのイメージを元にhello.war入りのイメージを作成するもの
│   ├── Dockerfile
│   ├── build.gradle   ...hello.warのビルドスクリプト
│   ├── gradlew
│   ├── gradlew.bat
│   └── src            ...hellow.warのソースコード
├── infra              ...tomcat7+apache2.4の入ったイメージを作成するもの
│   ├── Dockerfile
│   ├── apache.conf
│   │   ├── extra
│   │   └── httpd.conf
│   └── httpd-foreground
└── readme.md

warファイルの生成

warファイルのビルドにはgradleを使用しています。
gradleにはmavenなどの他のビルドツールと違って、gradleをインストールせずにビルドできるgradle wrapperという素敵な仕組みがありますが、本筋ではないので紹介だけして割愛します。ここではとりあえず「ソースに同梱されているgradlewスクリプトを叩けばいい」ということだけ理解してください。
warファイルのビルド内容についてはbuild.gradleに記述されていますが、これについても本筋ではないので割愛します。

取得したソースそのままでは代わり映えがしないのでvi src/main/webapp/index.jspでjspファイルを編集してみましょう。その後に以下のコマンドを実行してください。

$ cd docker-demo/app
$ ./gradlew war

すると./app/build/libs/hello.warが生成されます。

イメージのビルド

続いてDockerイメージを作成します。
ビルドするイメージに対する内容は./app/Dockerfileに書かれています。こちらについては後述します。

ビルドを実行
$ docker build .

Sending build context to Docker daemon 460.8 kB
Sending build context to Docker daemon 
Step 0 : FROM newgyu/tomcat:1.0.0
1.0.0: Pulling from newgyu/tomcat
e2a4fb18da48: Already exists 
58016a5acc80: Already exists 
  :
a48de4915c8d: Already exists 
Digest: sha256:473b2575f7a97c904ee1c3735891d85313ff254be617f41f21ca83002e84ba46
Step 1 : RUN rm -rf /usr/local/tomcat/webapps/ROOT
 ---> Running in 415983e2d95c
 ---> 851e0dd6ea1e
Removing intermediate container 415983e2d95c
Step 2 : COPY build/libs/hello.war /usr/local/tomcat/webapps/ROOT.war
 ---> 6ab8fbc5b09d
Removing intermediate container ed79995666c9
Successfully built 6ab8fbc5b09d

ということでイメージID6ab8fbc5b09dが出来ました。

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED              VIRTUAL SIZE
<none>              <none>              6ab8fbc5b09d        About a minute ago   640.9 MB

Dockerfileとビルド動作

docker buildでは引数に指定されたディレクトリにあるDockerfileを読み込んで動作します。
サンプルアプリケーションのDockerfileは以下の内容になっています。

./app/Dockerfile
FROM newgyu/tomcat:1.0.0

RUN rm -rf /usr/local/tomcat/webapps/ROOT
COPY build/libs/hello.war /usr/local/tomcat/webapps/ROOT.war

ここから上記Dockerfileの内容とdocker build時に出力された結果ログを突き合わせて解説していきます。
Dockerfileの記法の詳細については公式のリファレンスを参照してください。

FROM

まず注目すべきはFROMというインストラクションです。
ここにはどのイメージを元にして作成するかが書かれています。(オブジェクト指向でいうところの継承元ですね)自前のDockerイメージを作るときには必ず何かのベースイメージから作ることになるのでFROMは必須になります。

ログ
Step 0 : FROM newgyu/tomcat:1.0.0
1.0.0: Pulling from newgyu/tomcat
e2a4fb18da48: Already exists 
58016a5acc80: Already exists 
  :
a48de4915c8d: Already exists 
Digest: sha256:473b2575f7a97c904ee1c3735891d85313ff254be617f41f21ca83002e84ba46

part1docker runした時の動作と同じで、イメージファイルからコンテナを起動します。ローカルリポジトリに該当するイメージがなければ暗黙的にpullする動作も同じです。

RUN

RUNはイメージを作成する上で最も使われるインストラクションです。
見てわかると思いますが、RUNのあとにLinuxのコマンドを書きます。DockerfileはChefやAnsibleと異なり、DSLではなくLinuxコマンドを普通記述します。Linuxに慣れている人にとってはこの方が理解しやすいでしょう。

複数のRUNを書くこともできるし、一つのRUNで&&で区切って複数のコマンドを書くことも出来ます。

&&で複数書く例
RUN apt-get update \
    && apt-get install -y --no-install-recommends
RUNインストラクションを複数書く例
RUN apt-get update
RUN apt-get install -y --no-install-recommends

今回のサンプルではrmコマンドを実行する実行しています。

ログ
Step 1 : RUN rm -rf /usr/local/tomcat/webapps/ROOT
 ---> Running in 415983e2d95c
 ---> 851e0dd6ea1e
Removing intermediate container 415983e2d95c

この2種類の書き方には大差はありませんが、後述するコミットの単位が異ってきます。

COPY

ビルドするマシンのローカルにあるファイルをイメージにコピーします。

./app/Dockerfile
COPY build/libs/hello.war /usr/local/tomcat/webapps/ROOT.war

この例ではgradleでビルドしたhello.warROOT.warという名前にしてイメージ内にコピーします。
ローカルファイルのパスはDockerfileからの相対パスで指定します。

ログ
Step 2 : COPY build/libs/hello.war /usr/local/tomcat/webapps/ROOT.war
 ---> 6ab8fbc5b09d
Removing intermediate container ed79995666c9

docker commit

dockerのコンテナは実は変更をするたびにバージョン管理が出来ます。このバージョン管理の仕組みは先のビルド時の、

ログ
Step 1 : RUN rm -rf /usr/local/tomcat/webapps/ROOT
 ---> Running in 415983e2d95c
 ---> 851e0dd6ea1e
      ^^^^^^^^^^^^

このログ出力と密接に関係しています。

少し実験してみましょう。

コンテナでshellコマンドを実行

$ docker run -it newgyu/tomcat:1.0.0 /bin/bash
root@cd7240eac1a2:/usr/local/apache2# cd /usr/local/tomcat/
root@cd7240eac1a2:/usr/local/tomcat# ls -l webapps/
total 20
drwxr-xr-x  3 root root 4096 Oct 14 13:29 ROOT
drwxr-xr-x 14 root root 4096 Oct 14 13:29 docs
drwxr-xr-x  7 root root 4096 Oct 14 13:29 examples
drwxr-xr-x  5 root root 4096 Oct 14 13:29 host-manager
drwxr-xr-x  5 root root 4096 Oct 14 13:29 manager

newgyu/tomcat:1.0.0というイメージはtomcatをインストールしたばかりの状態なので、webappsディレクトリにtomcatデフォルトの

  • ROOT
  • docs
  • example
  • host-manager
  • manager

というWEBアプリケーションがインストールされた状態になっています。
そのうちのROOTを消してみます。

root@cd7240eac1a2:/usr/local/tomcat# rm -rf /usr/local/tomcat/webapps/ROOT/

そしてshellを終わりましょう。

root@cd7240eac1a2:/usr/local/tomcat# exit
exit

コンテナの状態をコミットする

さて、掲題のdocker commitです。
が、その前にdocker psで先ほど作業したコンテナのIDを確認しましょう。すでに終了させたコンテナなので-aオプションをつけます。

$ docker ps -a
CONTAINER ID        IMAGE                        COMMAND                CREATED             STATUS                       PORTS               NAMES
cd7240eac1a2        newgyu/tomcat:1.0.0          "/bin/bash"            21 minutes ago      Exited (130) 6 minutes ago                       lonely_ritchie      

cd7240eac1a2をコミットすると、

$ docker commit cd7240
c426b57d7bc11b89724b574a04b1ea8b49ba0ab5bdaf4b119bed17dae691db13
newgyu@newgyu-UX31E:~/Desktop/dockersample/app$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
<none>              <none>              c426b57d7bc1        3 seconds ago       640.6 MB

c426b57d7bc1というイメージが作成されましたね。

docker commitコマンドを使うことで、コンテナのある状態をローカルリポジトリの中のイメージとして保存することができるというものになります。つまりDockerfile,docker buildを使わなくても、
カチャカチャ ッターン
とすることでイメージが作れるのです。

ただし、これをやると「どうやって作ったのか不明なVMイメージ」と全く同じことになるので、最近では当然になってきた「Infrastructure As Code」を実践するためにDockerfileでイメージの作り方をコード化するようにしましょう。(食品でも生産地とか添加物とかを明示する義務があるように、インフラも見える化すべきですね)

さて、ここでdocker buildを振り返る

dockerのコンテナは実は変更をするたびにバージョン管理が出来ます。このバージョン管理の仕組みは先のビルド時の、

ログ
Step 1 : RUN rm -rf /usr/local/tomcat/webapps/ROOT
 ---> Running in 415983e2d95c
 ---> 851e0dd6ea1e
      ^^^^^^^^^^^^

このログ出力と密接に関係しています。

ここに話を戻しましょう。もうお分かりだと思いますが、docker buildの実行過程で行われることは上記で実験してみたのと同じでdocker commitでイメージを作成しているだけです。内部的にDockerfileを一行ずつコミットしながらイメージを作成しているわけです。
ここが理解できると、前述の、

複数のRUNを書くこともできるし、一つのRUNで&&で区切って複数のコマンドを書くことも出来ます。

この意味もわかってくるかと思います。つまりは結果は同じなのだけれど、履歴の残し方が変わってくるわけです。(gitでもどの単位でcommitしていくかを考えますよね?)

docker history

コミットをしているということは当然履歴を追跡することも可能です。先ほどビルドした

Successfully built 6ab8fbc5b09d

このイメージの履歴を見てみましょう。

$ docker history 6ab8
IMAGE               CREATED             CREATED BY                                      SIZE                         COMMENT
6ab8fbc5b09d        6 hours ago         /bin/sh -c #(nop) COPY file:0a2dfbf69ce2dab06   295.4 kB                     
851e0dd6ea1e        6 hours ago         /bin/sh -c rm -rf /usr/local/tomcat/webapps/R   0 B                          
a48de4915c8d        8 days ago          /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "/usr/l   0 B                          
8d614329fad3        8 days ago          /bin/sh -c #(nop) EXPOSE 80/tcp                 0 B
:                          

このイメージを作るために実行されたコマンドをコミット単位で見ることが出来ます。

DockerHubにイメージを登録してみよう

さて、こうして作成したイメージをリモートリポジトリであるDockerHubに登録してみましょう。

まずはDockerHubにユーザー登録

https://hub.docker.com/ から登録してください。メールアドレスがあればできるいつものやつです。

作ったイメージにタグ名をつける

DockerHubに登録する前に対象のイメージに名前(タグ)をつけてあげる必要があります。これはdocker tagコマンドを使用します。

Usage: docker tag [OPTIONS] IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]
$ docker tag 50ed3 newgyu/hoge:1.0.0
$ docker images
REPOSITORY                TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
newgyu/hoge               1.0.0               50ed314c079a        11 minutes ago      640.9 MB
引数 意味
IMAGE イメージのIDを指定します
REGISTRYHOST DockerHubにpushする場合は省略します。その他のレジストリにpushする場合はホスト名を指定します
USERNAME DockerHubのユーザー名を指定してください
NAME イメージ名を何か指定してください
TAG 通常は1.0などのバージョン番号を指定します。省略するとlatestとなります

作ったイメージをpushする

$ docker push newgyu/hoge:1.0.0
The push refers to a repository [newgyu/hoge] (len: 1)
50ed314c079a: Image push failed 

Please login prior to push:     <---- DockerHubにログインしろと言ってきます
Username: newgyu
Password: 
Email: newgyu@mail.com
WARNING: login credentials saved in /home/ec2-user/.docker/config.json
Login Succeeded
The push refers to a repository [newgyu/hoge] (len: 1)
50ed314c079a: Image already exists 
2a17d1069a42: Image successfully pushed 
a48de4915c8d: Image successfully pushed 

これでDockerHubにアップロードされたと思いますので、DockerHubのページを確認してみましょう。

https://hub.docker.com/r/ユーザーID/


というところで今回は、

  • Dockerイメージを作成する
  • DockerHubにイメージを登録する

ということをやってみました。

NewGyu
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした