Docker入門

# Docker入門

こんにちは！
今回は、Dockerについて学習をしたので記録として残します。
どなたかの参考になれば幸いです。

## Dockerとは何か？

Dockerは開発者とシステム管理者が開発のために使用するプラットフォームである。コンテナ化されたアプリケーションをデプロイして実行をする。

コンテナは、アプリケーションの実行に必要なものすべてをカプセル化する実行中のプロセスである。このようにDockerを利用すると、異なる環境でも簡単に移動や実行を行うことができる。

## Dockerイメージとは

イメージは、必要なすべてのものが含まれる、スタンドアロンで独立した軽量の実行可能なパッケージである。（コード、ランタイム、ツール、ライブラリ、設定など）

イメージは実行するアプリケーションであり、コンテナはイメージのランタイムインスタンスである。同じイメージから、さらに多くのコンテナを起動することができる。多くのアプリケーションイメージは、Docker hubで公開されているため、プリインストールされた様々なアプリケーション環境を素早く実行することが可能（WebサーバやDBサーバなど）

## Dockerのインストール

今回は、DockerとDocker composeのインストールをAmazon Linux2上にインストールを行います。

EC2上にAmazon Linux2のインスタンスを立ち上げてDockerのインストールを行います。

```bash
sudo dnf -y install docker
sudo DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker}
sudo mkdir -p $DOCKER_CONFIG/usr/local/lib/docker/cli-plugins
#v2.24.7 2024/3/12時点の最新
sudo curl -SL https://github.com/docker/compose/releases/download/v2.4.1/docker-compose-linux-x86_64 -o $DOCKER_CONFIG//usr/local/lib/docker/cli-plugins/docker-compose
#実行バイナリに対して実行権限を与えます。
sudo chmod +x /usr/local/lib/docker/cli-plugins/docker-compose
#dockerを起動
sudo systemctl start docker
sudo systemctl enable docker
#インストール結果をテストします。
sudo docker compose version
sudo docker version
```

## Dockerの主要なコマンド

`sudo docker info`  
システム上でのdockerの状態を確認

`sudo docker help`  
docker ヘルプ情報の参照

`sudo docker container help`  
docker container ヘルプ情報の確認

`sudo docker container ls`  
実行中のコンテナとdockerイメージをリストする

`sudo docker image ls`  
利用可能なイメージのリスト

`sudo docker container run hello-world` or  
`sudo docker run hello-world` is the oldest command  
Docker hubとの通信を含む、Dockerインストール全体をテストするには、docker containerを実行します。このコマンドを実行すると、ローカルでイメージを探し、ない場合は、Docker hubから検索してイメージをダウンロードする。

一度イメージをローカルに保存した場合は、ローカルを参照するため、docker hubからはプルは行わない。イメージが既に存在しているというメッセージが表示される。

`docker search [image-name]`  
docker CLIを使用してイメージを検索する

例として、nginxのイメージを検索

```console
[yunisan1211@ip-x.x.x.x ~]$ sudo docker search nginx
NAME                               DESCRIPTION                                     STARS     OFFICIAL
nginx                              Official build of Nginx.                        19686     [OK]
unit                               Official build of NGINX Unit: Universal Web …   25        [OK]
nginx/nginx-ingress                NGINX and  NGINX Plus Ingress Controllers fo…   88
nginxinc/nginx-unprivileged        Unprivileged NGINX Dockerfiles                  143
nginx/nginx-prometheus-exporter    NGINX Prometheus Exporter for NGINX and NGIN…   38
nginxinc/nginx-s3-gateway          Authenticating and caching gateway based on …   6
nginx/unit                         This repository is retired, use the Docker o…   64
nginx/nginx-ingress-operator       NGINX Ingress Operator for NGINX and NGINX P…   2
nginxinc/amplify-agent             NGINX Amplify Agent docker repository           1
nginx/nginx-quic-qns               NGINX QUIC interop                              1
nginxinc/ingress-demo              Ingress Demo                                    4
nginxproxy/nginx-proxy             Automated nginx proxy for Docker containers …   132
nginxproxy/acme-companion          Automated ACME SSL certificate generation fo…   130
bitnami/nginx                      Bitnami nginx Docker Image                      183
bitnami/nginx-ingress-controller   Bitnami Docker Image for NGINX Ingress Contr…   32
ubuntu/nginx                       Nginx, a high-performance reverse proxy & we…   112
nginxinc/nginmesh_proxy_debug                                                      0
nginxproxy/docker-gen              Generate files from docker container meta-da…   16
nginxinc/mra-fakes3                                                                0
kasmweb/nginx                      An Nginx image based off nginx:alpine and in…   7
nginxinc/nginmesh_proxy_init                                                       0
rancher/nginx-ingress-controller                                                   12
nginxinc/mra_python_base                                                           0
nginxinc/ngx-rust-tool                                                             0
```

`docker image pull redis:5.0.10`  

dockerではタグをつけることができ、タグによって、特定のバージョンのソフトウェアをダウンロードするなどといったことが可能。

`docker image pull redis`  

タグをつけない場合は、最新の安定バージョンがダウンロードされる

`docker container run redis`  
イメージからコンテナを実行し起動する
なお、ローカルにイメージがない場合は、Docker hubからダウンロードして実行しようとする。

例として、nginxのイメージがローカル上にある場合  
redisのイメージがローカル上にない場合のdocker container runの挙動をしたに貼り付けています。

```console
[yunisan1211@ip-x.x.x.x ~]$ sudo docker images
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
nginx        latest    e4720093a3c1   3 weeks ago   187MB
httpd        latest    2776f4da9d55   7 weeks ago   167MB
[yunisan1211@ip-x.x.x.x ~]$ sudo docker run nginx
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2024/03/11 18:25:08 [notice] 1#1: using the "epoll" event method
2024/03/11 18:25:08 [notice] 1#1: nginx/1.25.4
2024/03/11 18:25:08 [notice] 1#1: built by gcc 12.2.0 (Debian 12.2.0-14) 
2024/03/11 18:25:08 [notice] 1#1: OS: Linux 6.1.77-99.164.amzn2023.x86_64
2024/03/11 18:25:08 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 32768:65536
2024/03/11 18:25:08 [notice] 1#1: start worker processes
2024/03/11 18:25:08 [notice] 1#1: start worker process 29
^C2024/03/11 18:25:13 [notice] 1#1: signal 2 (SIGINT) received, exiting
2024/03/11 18:25:13 [notice] 29#29: exiting
2024/03/11 18:25:13 [notice] 29#29: exit
2024/03/11 18:25:13 [notice] 1#1: signal 17 (SIGCHLD) received from 29
2024/03/11 18:25:13 [notice] 1#1: worker process 29 exited with code 0
2024/03/11 18:25:13 [notice] 1#1: exit
[yunisan1211@ip-x.x.x.x ~]$ sudo docker container run redis
Unable to find image 'redis:latest' locally
latest: Pulling from library/redis
e1caac4eb9d2: Already exists 
7469c6c5b625: Pull complete
a3d1b68c4a62: Pull complete
152cbe749752: Pull complete
7218480dfba1: Pull complete
e61c48a0d344: Pull complete
4f4fb700ef54: Pull complete
82adb0efabd8: Pull complete
Digest: sha256:e647cfe134bf5e8e74e620f66346f93418acfc240b71dd85640325cb7cd01402
Status: Downloaded newer image for redis:latest
1:C 11 Mar 2024 18:25:26.783 # WARNING Memory overcommit must be enabled! Without it, a background save or replication may fail under low memory condition. Being disabled, it can also cause failures without low memory condition, see https://github.com/jemalloc/jemalloc/issues/1328. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
1:C 11 Mar 2024 18:25:26.783 # WARNING Your system is configured to use the 'xen' clocksource which might lead to degraded performance. Check the result of the [slow-clocksource] system check: run 'redis-server --check-system' to check if the system's clocksource isn't degrading performance.
1:C 11 Mar 2024 18:25:26.783 * oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1:C 11 Mar 2024 18:25:26.784 * Redis version=7.2.4, bits=64, commit=00000000, modified=0, pid=1, just started
1:C 11 Mar 2024 18:25:26.784 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf   
1:M 11 Mar 2024 18:25:26.785 * monotonic clock: POSIX clock_gettime
1:M 11 Mar 2024 18:25:26.785 * Running mode=standalone, port=6379.
1:M 11 Mar 2024 18:25:26.786 * Server initialized
1:M 11 Mar 2024 18:25:26.786 * Ready to accept connections tcp
^C1:signal-handler (1710181529) Received SIGINT scheduling shutdown...
1:M 11 Mar 2024 18:25:29.698 * User requested shutdown...
1:M 11 Mar 2024 18:25:29.698 * Saving the final RDB snapshot before exiting.
1:M 11 Mar 2024 18:25:29.702 * DB saved on disk
1:M 11 Mar 2024 18:25:29.703 # Redis is now ready to exit, bye bye...
```

### dockerでnginxサーバを立ち上げて、ローカルマシン上で確認してみる

nginxの起動  
`sudo docker container run -d --rm --name nginx nginx`

ポートを指定して起動する場合  
`sudo docker container run -p 8080:80 -d --rm --name nginx nginx`  

作成・起動・停止  

```bash
#dockerコンテナ作成
sudo docker container create -p 8080:80 --name nginx nginx
#dockerコンテナ起動
sudo docker container start nginx
#dockerコンテナ起動確認
sudo docker container ls
#dockerコンテナ停止
sudo docker container stop nginx
```

-p 指定ポート:デフォルトポート

-d(バックグラウンドで起動する)  
--rm(docker stopを掛けると自動的にコンテナが削除される)  
--name(任意の名前をコンテナに命名可能)  

起動されたdocker container nginxのIPを調べる  
`sudo docker inspect nginx | grep -i ipaddress`

停止するには  
`sudo docker container stop nginx`

停止されたか確認する  
`sudo docker container ls`

```console
[yunisan1211@ip-x.x.x.x ~]$ sudo docker container ls
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
[yunisan1211@ip-10-0-1-107 ~]$ sudo docker container run -d --rm --name nginx nginx
3bc9d1dc1609f59a35fc6f1e016fedb41d10fbe6cf9f59c6fde08fbbd8fc563a
[yunisan1211@ip-10-0-1-107 ~]$ sudo docker container ls
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS     NAMES
3bc9d1dc1609   nginx     "/docker-entrypoint.…"   8 seconds ago   Up 7 seconds   80/tcp    nginx
[yunisan1211@ip-10-0-1-107 ~]$ sudo docker container ps -a
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS                     PORTS     NAMES
3bc9d1dc1609   nginx     "/docker-entrypoint.…"   17 seconds ago   Up 16 seconds              80/tcp    nginx
3178bc38e40c   redis     "docker-entrypoint.s…"   3 minutes ago    Exited (0) 3 minutes ago             compassionate_mclaren
fa1680134b1f   nginx     "/docker-entrypoint.…"   4 minutes ago    Exited (0) 4 minutes ago             naughty_margulis
[yunisan1211@ip-10-0-1-107 ~]$ sudo docker help

Usage:  docker [OPTIONS] COMMAND

A self-sufficient runtime for containers

Common Commands:
  run         Create and run a new container from an image
  exec        Execute a command in a running container
  ps          List containers
  build       Build an image from a Dockerfile
  pull        Download an image from a registry
  push        Upload an image to a registry
  images      List images
  login       Log in to a registry
  logout      Log out from a registry
  search      Search Docker Hub for images
  version     Show the Docker version information
  info        Display system-wide information

Management Commands:
  builder     Manage builds
  buildx*     Docker Buildx (Docker Inc., v0.0.0+unknown)
  compose*    Docker Compose (Docker Inc., v2.24.7)
  container   Manage containers
  context     Manage contexts
  image       Manage images
  manifest    Manage Docker image manifests and manifest lists
  network     Manage networks
  plugin      Manage plugins
  system      Manage Docker
  trust       Manage trust on Docker images
  volume      Manage volumes

Swarm Commands:
  swarm       Manage Swarm

Commands:
  attach      Attach local standard input, output, and error streams to a running container
  commit      Create a new image from a container's changes
  cp          Copy files/folders between a container and the local filesystem
  create      Create a new container
  diff        Inspect changes to files or directories on a container's filesystem
  events      Get real time events from the server
  export      Export a container's filesystem as a tar archive
  history     Show the history of an image
  import      Import the contents from a tarball to create a filesystem image
  inspect     Return low-level information on Docker objects
  kill        Kill one or more running containers
  load        Load an image from a tar archive or STDIN
  logs        Fetch the logs of a container
  pause       Pause all processes within one or more containers
  port        List port mappings or a specific mapping for the container
  rename      Rename a container
  restart     Restart one or more containers
  rm          Remove one or more containers
  rmi         Remove one or more images
  save        Save one or more images to a tar archive (streamed to STDOUT by default)
  start       Start one or more stopped containers
  stats       Display a live stream of container(s) resource usage statistics
  stop        Stop one or more running containers
  tag         Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
  top         Display the running processes of a container
  unpause     Unpause all processes within one or more containers
  update      Update configuration of one or more containers
  wait        Block until one or more containers stop, then print their exit codes

Global Options:
      --config string      Location of client config files (default "/root/.docker")
  -c, --context string     Name of the context to use to connect to the daemon (overrides DOCKER_HOST env var and default context set with "docker context use")     
  -D, --debug              Enable debug mode
  -H, --host list          Daemon socket to connect to
  -l, --log-level string   Set the logging level ("debug", "info", "warn", "error", "fatal") (default "info")
      --tls                Use TLS; implied by --tlsverify
      --tlscacert string   Trust certs signed only by this CA (default "/root/.docker/ca.pem")
      --tlscert string     Path to TLS certificate file (default "/root/.docker/cert.pem")
      --tlskey string      Path to TLS key file (default "/root/.docker/key.pem")
      --tlsverify          Use TLS and verify the remote
  -v, --version            Print version information and quit

Run 'docker COMMAND --help' for more information on a command.

For more help on how to use Docker, head to https://docs.docker.com/go/guides/
[yunisan1211@ip-10-0-1-107 ~]$ sudo docker inspect nginx | grep -i ipaddress
            "SecondaryIPAddresses": null,
            "IPAddress": "172.17.0.2",
                    "IPAddress": "172.17.0.2",
[yunisan1211@ip-10-0-1-107 ~]$ curl 172.17.0.2
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</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>

[yunisan1211@ip-10-0-1-107 ~]$ sudo docker container stop nginx
[sudo] password for yunisan1211: 
nginx
[yunisan1211@ip-10-0-1-107 ~]$ sudo docker container ls
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
[yunisan1211@ip-10-0-1-107 ~]$
```

EC2のパブリックIPでアクセスするとNginxのwellcomeページが表示された。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247592/151d624e-c8ea-cc4d-1c58-718a9d2339c9.png)


### dockerコンテナでalmalinuxを起動して、シェルにはいる

#### 一連の流れ

- AlmaLinuxをDocker hub上で探す
- イメージをダウンロードする
- ダウンロードしたイメージの確認
- イメージからコンテナを作成する
- 作成後の確認
- コンテナを起動しシェルに入る、操作する
- シェルからログアウトする
- コンテナを削除する

```bash
#AlmaLinuxをDocker hub上で探す
sudo docker search almalinux
#NAME                          DESCRIPTION                                     STARS     OFFICIAL
#almalinux                     The official build of AlmaLinux OS.             145       [OK]

#イメージをダウンロードする
sudo docker pull almalinux
#Using default tag: latest
#latest: Pulling from library/almalinux
#28130cb29ede: Pull complete
#Digest: sha256:d7f8aa1c5ff918565fa1114d16e27b03fe10944a422e2943a66f6f4a275fa22c
#Status: Downloaded newer image for almalinux:latest
#docker.io/library/almalinux:latest

#ダウンロードしたイメージの確認
sudo docker image ls
#almalinux    latest    7407e03f7ffc   3 months ago   184MB

#イメージからコンテナを作成する
sudo docker container create --name almalinux almalinux

#作成後の確認
sudo docker container ps -a
#CONTAINER ID   IMAGE       COMMAND                  CREATED              STATUS                      PORTS     NAMES
#7da913b4a40a   almalinux   "/bin/bash"              About a minute ago   Created                               almalinux

#コンテナを起動しシェルに入る、操作する
sudo docker container run -it almalinux bash
#[root@f7ddcc59d5ee /]# cat /etc/os-release 
#NAME="AlmaLinux"
#VERSION="9.3 (Shamrock Pampas Cat)"
#ID="almalinux"
#ID_LIKE="rhel centos fedora"
#VERSION_ID="9.3"
#PLATFORM_ID="platform:el9"
#PRETTY_NAME="AlmaLinux 9.3 (Shamrock Pampas Cat)"
#ANSI_COLOR="0;34"
#LOGO="fedora-logo-icon"
#CPE_NAME="cpe:/o:almalinux:almalinux:9::baseos"
#HOME_URL="https://almalinux.org/"
#DOCUMENTATION_URL="https://wiki.almalinux.org/"
#BUG_REPORT_URL="https://bugs.almalinux.org/"

#ALMALINUX_MANTISBT_PROJECT="AlmaLinux-9"
#ALMALINUX_MANTISBT_PROJECT_VERSION="9.3"
#REDHAT_SUPPORT_PRODUCT="AlmaLinux"
#REDHAT_SUPPORT_PRODUCT_VERSION="9.3"

#シェルを起動させたまま抜けたい場合
Ctrl + P + Q

# 再び入りたい場合
sudo docker container exec -it [container-id or name] bash

#シェルを終了する場合
exit

#起動させたままの場合は停止する
sudo docker container stop almalinux

#dockerコンテナを削除する
sudo docker container rm almalinux
```

officialイメージであることを確認した

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247592/5dc57d2b-d1ad-ddb2-fe1b-dacc6406af9b.png)


### dockerイメージとコンテナの一覧確認コマンド

```bash
#ローカルにあるdockerイメージの一覧取得
sudo docker image ls

#実行中のコンテナ
sudo docker container ls

#停止および終了も含めたコンテナの表示
sudo docker container ls -a or --all
sudo docker container ps -a or --all

#特定の列の絞り込み
sudo docker container ls -a -f status=exited

#特定の列の絞り込みとコンテナIDのみ表示
sudo docker container ls -a -f status=exited -q
```

### dockerイメージとコンテナの削除コマンド

```bash
#削除前に停止をする container-idは最初の4文字でOK！
sudo docker container stop [container-id or name]

#削除
sudo docker container rm [container-id or name]

#起動中のコンテナを強制的に削除 -f=fource
sudo docker container rm -f [container-id or name]

#終了したコンテナを全て削除する
sudo docker container rm $(docker container ls -a -f status=exited -q)

#docker imageを削除する
sudo docker image rm [image-id or repo-name] #new
sudo docker rmi [image-id or repo-name] #old

#未解決のイメージ、停止したコンテナ、未解決のビルド キャッシュ、および使用されていないネットワークを削除する
docker system prune

#未使用のイメージも削除します
docker system prune -a
```

### シェル系の操作

```bash
#起動後シェルに入りたいとき（コンテナがない場合）-itは必須！
sudo docker container run --name almalinux alumalinux -it bash

#シェルを起動させたまま抜けたいとき
Ctrl + P + Q

#再度シェルに入りたい場合
sudo docker container exec [container-id or name]

#停止させる場合
sudo docker container stop [container-id or name]

#起動させる場合
sudo docker container start [container-id or name]

#シェルに入らずに操作をさせたいとき
sudo docker container exec [container-id or name] コマンド
```

### ログの確認

```bash
#ログの確認
sudo docker container logs [id or name]

#ログを継続して確認
sudo docker container logs -f [id or name]
```

### カスタマイズしたコンテナのイメージ化

docker commitを使用してコンテナをイメージ化する  
-m コミットメッセージ  
-a 作成者の名前  
yunilab ⇒　イメージのもとになるコンテナ  
yuukun1211/my_almalinux:latest ⇒イメージの名前  
docker hunのアカウント/カスタムイメージ名:バージョンとしたほうがよい。

```bash
sudo docker commit -m "nmap installed" -a "yuki.sakai" yunilab yuukun1211/my_almalinux:latest
#sha256:a60df9cc54772dd98ced09c98b5ac043a3975505549bd7b9c6dbd5998d01269d
sudo docker image ls
#REPOSITORY                TAG       IMAGE ID       CREATED          SIZE
#yuukun1211/my_almalinux   latest    a60df9cc5477   14 seconds ago   251MB
#almalinux                 latest    7407e03f7ffc   3 months ago     184MB
sudo docker container run -it yuukun1211/my_almalinux
[root@b055860a7529 /]# nmap
Nmap 7.92 ( https://nmap.org )
```

`docker image tag repo new_reponame`  
tag付けをすることでコピーを作成することができる。

new_reponameは通常、自分のリポジトリ/元のリポジトリ名:versionとする。

### カスタムリポジトリをdocker hubにアップロードする

```bash
#docker hubにログインする
sudo docker login
#カスタムイメージをpushする
sudo docker image push account/repo_name:tag
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247592/35075e08-8123-96c1-459e-947e4c65e78f.png)


docker hubをみるとアップロードができている！

### Dockerfile

Dockerfileとは、Dockerイメージを作成するためのテキストファイルである。Dockerfile内には、基本となるOS、インストールする必要があるSW、コピーするファイル、ディレクトリ、開くポート、実行するコマンドなど、新しいDockerイメージを作成するために必要な指示が含まれている。

Dokcerfileの書き方としては、「FROM」「RUN」「CMD」などのインストラクションに引数を記述し作成する。

#### FROM

「FROM」インストラクションは、Dockerfileの中で一番最初に記述されるべき命令で、新たに作成するDockerイメージのベースとなるイメージを指定する。  
`#FROMでイメージを指定 イメージの名前:タグ名（バージョン）
FROM nginx:latest`

#### RUN

「RUN」インストラクションはDockerイメージのビルド時にシェルコマンドを実行するための命令である。  
この命令を使用することで、イメージにソフトウェアをインストールしたり、セットアップの手順を実行したりすることができる。

`#RUNでシェルコマンドを実行する
RUN apt update && apt install -y curl`

「RUN」インストラクションは実行ごとに新しいレイヤを作成してその上でコマンドを実行するため、多くの「RUN」を持つDockerfileは多くのレイヤからなるイメージを作成しイメージのサイズが大きくなる。そのため、レイヤ数は最小限にすることが望ましい。

このため、複数のコマンドを一度にまとめて実行するときは、「&&」でつなぎ、「RUN」を減らし、複数行になるときは\をつかい可視性をあげる。

#### CMD

「CMD」インストラクションは、Dockerコンテナが実行された時にデフォルトで実行するコマンドを定義する。原則として末尾に書く。複数書いても一番最後の命令しか処理されないことに注意する。

```dockerfile
# 書式：CMD ["実行ファイル", "パラメータ1","パラメータ2"] 
$ CMD ["apachectl","-D","FOREGROUND"]
```

#### COPYとADD

「COPY」インストラクションは、ホスト（ローカル）のファイルやディレクトリをDockerイメージにコピーする。  
具体的な使い方としては、ソースコードや設定ファイルはローカルで作成してCOPYを使ってDockerイメージにコピーして使用する。

「ADD」インストラクションは、自動的にtar展開してからコピーを行う。（ADDはリモートファイルを追加できる点もCOPYと異なる）

```dockerfile
# 書式：　COPY [コピー元][コピー先]
①ファイルをファイルに
COPY　index.html /mydir/index.html
②ファイルをディレクトリ以下に
COPY　index.html　/mydir/
③ディレクトリをディレクトリに
COPY src/ /mydir/
# 書式： ADD[追加元][追加先]
#tarファイルを展開
ADD ./hoge/hoge.tar /hoge/
#通常はCOPYコマンドを使用し、tarファイルを扱うときやリモートファイルを扱う際はADDを使用する。
```

#### ARGとENV

「ENV」インストラクションは、Dockerfile内で環境変数を設定するために使用される。設定された環境変数は、その後のDockerfileの中で使用することができ、また生成されたDockerイメージから作成されるすべてのコンテナで利用することが可能。

「ARG」インストラクションは、同一Dockerfile内でのみ使用可能である

つまり、そのコンテナ全体で共有したいような変数を事前に決めておきたい場合は、ENVを使用し、インストールするSWのバージョンといったビルド時に必要なもの等はARGという認識でよさそうです。

```dockerfile
# 書式：　ENV [環境変数名]　＝　[値]
ENV MYSQL_USER=yunilab
ENV MYSQL_PASSWORD=hogefoobar
# 書式：　ARG [変数名] = [値]
ARG VERSION="18.00"
FROM ubuntu:${VERSION}
```

#### WORKDIR

「WORKDIR」インストラクションは、コマンドを実行する作業ディレクトリを指定する。

```dockerfile
# 書式：　WORKDIR [ディレクトリのパス]
WORKDIR /app
#移行は/appでの操作が行われる。
```

「WORKDIR」インストラクションを使用することで、Dockerfileが読みやすくなり、絶対パスを何度も書く手間を省くことができる。

#### EXPOSE

コンテナが特定のポートをlistenしていることをDockerに通知する役割を果たす。

!実際にEXPOSE命令自体は、ポートを公開するわけではなく、イメージ作成者とコンテナ運用者のドキュメント的な側面があるため、実際のポートを公開するには、dokcer run -pを使用する必要があることに注意する

```docker
#80番ポートをlistenしていることを通知
EXPOSE 80
```

#### VOLUME

VOLUMEを使用することにより、コンテナ内のデータをホストマシン上に永続保管することが可能。

マウントする位置を示す。「docker run -v /foo/bar:/var/lib/mysql」と同じ [ホスト上のディレクトリ:コンテナ内のディレクトリ]
VOLUME["/foo/bar/"] or VOLUME /foo/bar/のような指定が可能。

```docker
FROM ubuntu
RUN mkdir/myvol \
&& echo "hello world" > /myvol/hogehoge
VOLUME /myvol
```

```Dockerfile
#1コマンドごとにイメージレイヤーが上乗せされる
#docker historyコマンドで確認ができる

#FROMでイメージを指定 イメージの名前:タグ名（バージョン）
FROM nginx:latest
#COPYでホストからファイルをイメージにコピーする
COPY index.html index.html
#RUNでシェルコマンドを実行する
RUN apt update && apt install -y curl
#ENVで環境変数を指定
ENV env_key env_value
#CMDでコンテナが起動したときに最初に起動するコマンド
CMD ["nginx", "-g", "deamon", "off"]
```

作成したDockerfileの起動は下記のように行う
`docker build . -t example:latest`

### Docker Compose

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247592/8cb83d12-1430-823c-a4c7-1854778caa4c.png)

Docker Composeとは、これまでDocker runなどでコンテナ一つごとにコマンドを打って操作していたものを、composeを用いることにより、複数のコンテナで構成されるアプリケーションについて、Dockerイメージのビルドや各コンテナの起動・停止などをより簡単に行えるようにするツールといえる。

#### コンテナを起動するまでの流れ

##### Dockerfileの作成

docker-compose.ymlファイルで直接イメージを指定すれば、Docker composeでコンテナを起動するためのDockerfileは必要ないですが、既存のイメージに対して追加の設定やカスタマイズを行いたい場合は、Dockerfileを作成し、それをdocker-compose.ymlから参照する。

##### docker-compose.ymlの作成

docker-compose.ymlとはDocker Composeの設定ファイルであり、これから作成するコンテナの初期状態を「ports:」「volumes:」などYAML形式を用いて定義する。  
また、このファイルは通常、プロジェクトのルートディレクトリに配置するのが一般的である。

docker-compose.ymlを使用することにより、複数のコンテナで構成されるアプリケーションの全体像を一目で把握でき、さらに一つのコマンドですべてのコンテナを起動したり、停止するといったことも可能になる。

##### docker-composeコマンドでコンテナ起動

docker-compose.ymlファイルが存在するディレクトリでdocker compose upコマンドを実行すると、docker-compose.ymlファイルに記述されたすべてのサービス（コンテナ）をビルドし、起動することができる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247592/c1a6e6c7-2a9a-6f77-497c-763b47dc7a68.png)

##### docker-compose.ymlファイルの書き方

```yaml
services: # （１）
  db:
    image: mysql:5.7 # （２）
    volumes: # （４）
      - db_data:/var/lib/mysql 
    restart: always
    environment: # （６）
      MYSQL_ROOT_PASSWORD: root_password
      MYSQL_DATABASE: your_database
      MYSQL_USER: user_name
      MYSQL_PASSWORD: user_password

  web:
    build: ./rails_project # （３）
    command: bundle exec rails s -p 3000 -b '0.0.0.0' # （９）
    volumes: # （４）
      - .:/myapp
    ports: # （７）
      - "3000:3000"
    depends_on: # （８）
      - db
      
volumes: # （５）
    db_data:
```

###### services

ここでは、作成したいサービス（コンテナ）を列挙する  
サンプルでは「web」と「db」という名前で2つのコンテナについて、それぞれ設定が記述されています。

```yaml
services:
  db: #service_name

  web: #service_name
```

サービス名は任意の名前を付けることができるが、「そのサービスが何を示しているか理解しやすい名前を付けること」「サービス名をほかのサービスから参照している場合があるので、変更する場合は参照されているサービス名も変更すること」に気を付けること。

###### image

既存のイメージに対して追加の設定やカスタマイズを行う必要がない場合、image:に続いて、Dockerイメージを指定することで、そのイメージよりビルドを行います。

`image: mysql:5.7 #イメージ名:タグ`

###### build

image:よりビルドするのではなく、用意したDockerfileよりビルドする場合、build:へumlファイルが置いてあるディレクトリからDockerfileが置いてあるディレクトリへの相対パスを記述します。

`build: ./rails_project #Dockerfileがあるディレクトリへの相対パス`

###### volumes【サービス内にある方】

volumesはデータをコンテナの外に保存するための設定項目であり、ホストにもデータを共有することでデータの永続性を可能する。

```yaml
#dbコンテナ
volumes:
  - db_data:/var/lib/mysql #ホストディレクトリ：コンテナ内ディレクトリ
#webコンテナ
volumes:
  - .:/myapp
```

volumesはホスト側のディレクトリとコンテナ内のディレクトリをマウントするために使用され、ホスト上で変更を行うとリアルタイムにコンテナ内にも反映される。

###### volumes【トップレベルで指定されている方】

ここでのvolumesはDocker Composeにボリュームを作成するように指示します。そしてここで定義されたボリュームはサービス内のvolumesで使用することができ、サンプルにおいてもdbコンテナにおいて使用されています。

```yaml
volumes:
  db_data:
```

volumes:を使うとデータはDockerコンテナの起動・停止のサイクルから独立して保存・管理することができるため、コンテナが削除されてもボリュームに保存されたデータは保持される。

ボリュームの考え方は結構難しいので、以下の記事を見たほうがよろしいかと。。
<https://qiita.com/aki_55p/items/63c47214cab7bcb027e0>

-vオプションと--mountオプションの項目が参考になった。

###### environment

environmentは、Dockerコンテナ内で使用される環境変数を設定するために使用する。  
Dockerコンテナはホストの環境と完全に分離されて動作するため、コンテナ内部で環境変数を設定する必要がある。

```yaml
  environment: 
      MYSQL_ROOT_PASSWORD: root_password
      MYSQL_DATABASE: your_database
      MYSQL_USER: user_name
      MYSQL_PASSWORD: user_password
```

###### ports

portsの設定では、ホストマシンとDockerコンテナ間でのネットワークポートのマッピングを指定する。  
指定する形式は「ホストマシンのポート番号：コンテナのポート番号」となる

```yaml
    ports: 
      - "3000:3000" # ホストマシンのポート番号:コンテナのポート番号
```

###### depends_on

depends_onはサービス間の依存関係を定義するために使用し、Docker Composeに指定したサービスが他の1つ以上のサービスに依存していることを伝えることができる。  
その結果、Docker Composeは、そのサービスを開始する前に依存しているすべてのサービスが先に開始されていることを確認してくれる。

```yaml
   # (webコンテナ)
   depends_on: 
     - db
```

上記の内容では、webコンテナがdbコンテナに依存しているので、dbコンテナが先に開始されることをDocker Composeは確認します。

###### command

commandはサービスコンテナが起動したときに実行するコマンドを指定する

`command: bundle exec rails s -p 3000 -b '0.0.0.0'
`

##### Docker Composeコマンドで操作する

###### up （コンテナ作成・起動）

`docker compose up #イメージが存在しないときはビルドする`

オプションでは以下の2つがよくつかわれる。

- --build イメージをビルドした上でコンテナを作成・起動する
- -d コンテナをバックグラウンドで起動させる

```bash
docker compose up --build 
docker compose up -d
```

###### ps (コンテナ一覧表示)

停止中を含めたコンテナの一覧を表示をさせたい場合は、-aオプションを付ける。

```bash
docker compose ps    　　# コンテナの一覧を表示
docker compose ps -a 　 #停止中を含めたコンテナの一覧を表示
```

###### logs (ログを表示)

logsコマンドの後に、サービス名を指定することでログを表示させる

`docker compose logs web` #サービス名を指定`

###### run (コンテナ作成後、コマンドを実行)

runコマンドの後に、サービス名とコマンドを指定することで、コンテナを作成して1度だけコマンドを実行する。

`docker compose run web ruby app.rb #サービスとコマンドを指定`

###### exec (コマンドを実行)

起動中のコンテナでexecコマンドの後に、サービス名とコマンドを指定することでコマンドを実行する。

`docker compose exec web cat /etc/httpd/httpd.conf` #サービスとコマンドを指定`

###### down (コンテナを停止・削除)

downコマンドを付けるだけで、upコマンドで作成されたコンテナを停止・削除する。

`docker compose down`

ここまでで、Dockerに必要な一通りの知識は学べたかと思います。
あとは自分でコンテナを作成したり、いろいろトライしてみて身につけていくことをおすすめします！

私自身もDockerという領域に初めてダイブしたので、これからも学習を続けていきたいと思います！！