dockerについて
今回はdockerについてまとめていきます。
業務で使う機会が増えてきており猛勉強中です。
「dockerとは」というところからいきましょう。

dockerとは一言でいうと「開発環境をみんなで共有して、環境構築を楽にしましょう」というツールだと認識してます。
通常なにかものを作る際には、チームで開発を進めていきますよね。そのときにAさんのPCにある環境とBさんのPCにある環境ってそれぞれで環境を作っているので、AさんのPCではそのプログラムは動くけど、BさんのPCではそのプログラムは動かないみたいなことが起こってしまいます。
例えば、Pythonを使うにしても、PCにPythonのパッケージをインストールしないと動かないように、AさんのPCにもBさんのPCにもPythonのパッケージをインストールしないと動きません。

では、全く同じ環境をつくればいいのでは?と思うかもしれませんが、それはとても大変な作業なことは明白ですよね。
PCのOSも違うかもしれないし、そのプログラムを動かすためには何十、何百のパッケージが紐付いて動いているプログラムかもしれません。それを一個づつインストールしていってなんてやっていたら環境構築だけで嫌になってしまいます。
そこで「docker」の出番です。
dockerは「コンテナ」という単位で開発環境を構築することができ、そのコンテナをファイルみたいに人に渡すことができます。なので、開発環境ごと渡すことで他の開発者はそのコンテナを参照して、すぐ開発に入ることができるということです。=環境の構築不要。

正確には、「コンテナ」を「dockerimage」というimageファイルにまとめて人に渡すことができます。
これがdockerの基本的な使い方です。
なので、まとめると
- たくさんの人と同じ環境で開発することができるため、環境構築がめちゃめちゃ楽になる
- 環境が異なることによるバグは発生しない
- 開発業務に集中できる
以上のようなメリットがあります。
そして無料で使えるツールなので、チーム開発にはもってこいのツールですよね。
使ってみよう
実際にdockerをインストールして使ってみましょう。
※OSはMacです。
dockerHubの登録
dockerhubは、githubのようにimageファイルをpush、pullできるようなサービスです。ここから使いたいimageファイルをとってきたりすることができます。
手順に沿ってアカウント登録をしてください。
dockerのインストール
https://hub.docker.com/editions/community/docker-ce-desktop-mac
こちらもmac版をインストールしていきます。
インストールが完了すると右上のアイコンにdockerのマークがでてきます。これで準備完了です。


docker pull <image名>
それではターミナルを開いてdockerを実行してみます。
まずはdocker loginでdocker hubにログインします。
そのあとにdocker pullコマンドでubuntuのimageファイルを落としてきましょう。docker imagesでimageのリストが表示できます。
docker login
docker pull ubuntu
docker images

image名=レポジトリ名です。TAGはバージョンになります。
逆に作ったものをdocker push <image名>でhubにプッシュすることもできます。
docker run –name <コンテナ名> -it <image名> <コマンド名>
imageファイルをrunしてコンテナを作成します。
–nameオプションでコンテナに名前をつけることができます。省略すると適当な名前が勝手につけられます。-itオプションでコマンド名を指定することができます。-itは-iがインプット可能、-tはstdinの意味をもっています。省略するとデフォルトコマンドが実行されます。
docker run --name ubuntu-test -it ubuntu bash

その他に使うオプションとして、
「docker run -d <image名>」=dockerを裏側で動かす=up状態にしておく。
「docker run –rm <image名>」=dockerコンテナから離脱したときに自動でコンテナを削除する。
dockerコンテナから抜ける際は
exit
ctrl+p+q(detach)
で抜けます。違いは、detach=コンテナを起動させておくか、exit=完全に切るかの違いになります。
基本はexitで抜けて、完全に切る方法のほうが多いです。
またスタートしたい場合は、
exit
→docker restart <コンテナ名>
→docker exec -it <コンテナ名> <コマンド名>
detach
→docker attach <コンテナ名>
で戻れます。
docker ps -a
dockerコンテナの一覧を表示できます。
docker ps -a

docker stop <コンテナ名>
起動中のdockerコンテナを停止できます。
docker stop <コンテナ名>

docker rm <コンテナ名>
dockerコンテナを削除できます。
docker rm <コンテナ名>

一気に削除したい場合は、「docker system prune」を使います。
docker exec -it <コンテナ名> <コマンド名>
起動中のコンテナに再度入って、コマンドを実行する
docker exec -it <コンテナ名> <コマンド名>

docker image作成編
ここからが本題です。dockerは自分の環境構築を楽するために使用するというのを冒頭でお伝えしました。
なので、dockerhubからとってきたimageに自分の追加したいパッケージを加えて新しいimageを作るのが通常の使い方になります。
その設定ファイルを「Dockerfile」といいます。
詳しくは後述しますが、dockerは自分で作成した「Dockerfile」をbuildすることにより、自分のdocker imageを作成し、そのimageをrunすることによって、コンテナ化するというフローになります。イメージ的には以下のような感じ。

なので、一番重要なのは「Dockerfile」に必要な機能やパッケージを記載していく箇所になります。
なにかフォルダを別途作成して、「Dockerfile」というファイルを作り、実際に書いていきましょう。
FROM
FROM句でどのimageから作り出すか指定します。
ubuntuやlinuxなどのOSなど、なにか他のimageを土台に作っていくのが基本です。
例)
FROM ubuntu:latest
RUN
実行したいコードを記載していきます。通常はインストールしたいパーケージなどを記載します。
例)
RUN apt-get update && apt-get install -y vim
WORKDIR
ディレクトリを移動して作業したいときに使用します。
例)
WORKDIR /develop
ENV
環境変数を指定したいときに使用します。PATHを通すときに使用するのが多いです。
例)
ENV PATH /develop/python3/bin:$PATH
COPY
HOSTからコンテナへファイルやフォルダをコピーしたいときに使用します。
例)
COPY ./test.sh /new_dir/
ADD
tarフォルダなど圧縮ファイルをコンテナに送り、解凍したいときなどに使用します。コンテナへ送る際は大量のデータを送ることになり、大きなファイルを贈ろうとするとそれだけ作成に時間がかかります。そのためなるべくファイルを小さくして送るのがよいとされています。
ADD ./test.tar /new_dir/
CMD
最後に実行したいコマンド名(コンテナのデフォルトコマンド)を記載します。
例)
CMD ["/bin/bash"]
ENTRYPOINT
なにかファイルを直接実行したいときなどに使用します。run時にデフォルトコマンドを上書きしないので、コマンドとして実行することができます。
例)
ENTRYPOINT ["./test.sh"]
その他Dockerfileを作成するときに注意すること
・パッケージのインストールでインタラクティブに選択させるようなものを回避するようにオプションを駆使して、記載する
例) sh -b 指定でインタラクティブ操作、-p PREFIXでインストールする先のフォルダを指定する
・Dockerfileを作るときは一気にすべて書くのではなく、まずは書けるところまで記載し、書き方がわからない(どのコマンドを実行すれば正しく動作するか不明なもの)は、一回サーバーに入って実行してみて確認してから、再度Dockerfileに記述していく。開発のときと同じ用にフローを書いて細かくbuildして確かめながら構築していくのが一番はやく正確に構築できる。
例)
①ubuntu取得
②apt-getで必要なパッケージをインストール
③作業用ディレクトリに移動
④jupyterをダウンロードして、shellの実行
⑤ダウンロードしたファイルの削除
⑥PATHを通す
⑦pipのupgrade
⑧rootに戻る
⑨jupyterの起動
↓
FROM ubuntu:latest
RUN apt-get update && apt-get install -y \
sudo \
wget \
vim
WORKDIR /opt
RUN wget https://repo.continuum.io/archive/Anaconda3-2019.10-Linux-x86_64.sh && \
sh Anaconda3-2019.10-Linux-x86_64.sh -b -p /opt/anaconda3 && \
rm -f Anaconda3-2019.10-Linux-x86_64.sh
ENV PATH /opt/anaconda3/bin:$PATH
RUN pip install --upgrade pip
WORKDIR /
CMD ["jupyter", "lab", "--ip=0.0.0.0", "--allow-root", "--LabApp.token=''"]
Dockerfileの例
FROM ubuntu:latest
RUN apt-get update && apt-get install -y vim
WORKDIR /develop
ENV PATH /develop/python3/bin:$PATH
COPY ./test.sh /new_dir/
CMD ["/bin/bash"]
docker build <directory>
Dockerfileができたら、そのDockerfileがあるフォルダを指定してdocker buildします。dockerはDockerfileがあるフォルダごとコンテナを作成する仕様になっていて、このフォルダをbuild contextと言います。

例)
docker build -t <image> <directory>
↓
docker build -t test-develop .
-tオプションでimageに名前をつけます。
また、build context以外にDockerfileがあって、それを指定してbuildしたい場合は-fオプションですることもできます。

docker build -f <dockerfilepath> <build context>
↓
docker build -f ../docker-set/Dockerfile .

docker run オプション編
docker runする際によく使用するオプションを記載します。
-v <HOST path>:<コンテナ path>
ホストのファイルシステムをコンテナ側にマウントします。要するにHOST側のファイルをコンテナ側でも閲覧編集できるようにします。
コンテナの使い方として通常スクリプトなどはコンテナに入れる必要性がないので、それぞれのHOSTで持っておくのがセオリーです。通常はgit管理だと思うので、git cloneでファイルを落としてくるかと思います。コンテナには不必要なものはいれないというのがベストプラクティスです。(ただし、WEBアプリケーションなどの本番環境サーバーにコンテナをいれる場合はコードも含みます)

例)
docker run -it -v ~/develop-code:/new_dir test
※パスは絶対パスで指定する。コンテナ側に対象のディレクトリがない場合は自動で作成されます。
-u <user-id>:<group-id>
ユーザーIDとグループIDを指定してコンテナをrunします。
これは上記のマウントの際もそうですが、特にユーザーを指定しなかった場合はroot権限での作成になるので、だれでもそのファイルを編集できてしまいます。なのでチームで同じコンテナを使用する際には、自分のhostにはいっているファイルも別の人が編集できてしまうというわけです。
例)
docker run -it -u $(id -u):$(id -g) -v ~/develop/test/moute:/created_in_run test
※ユーザーIDとグループIDは変数で指定します。
-p <hostport>:<containerport>
HOSTのポート番号とコンテナのポート番号を記載して、どのコンテナにアクセスできるようにするか指定します。通常一つのサーバーに複数のコンテナを用意し、それぞれのコンテナにWEBサービスを乗っける形かと思います。なので、そのコンテナにWEBブラウザからアクセスしたいときはポート番号を記載してrunする必要があります。

例)
docker run -it -p 8888:8888 --rm jupyter/datascience-notebook bash
まとめ
dockerについてまとめていきました。
次回は、AWSのEC2上にdocker環境を構築してみたいと思います。
その次は、ECSについて勉強していきます。