- 投稿日:2021-03-05T23:13:27+09:00
コンテナチェリーなのでDockerを基礎から学び始めた①
こんにちは、コンテナ童貞のすずきです。業務でDockerなど使ったことはありません。
この時点で、この記事を読んだ9割の現役エンジニアの方々は、私のことをコンテナも知らないレガシー雑魚野郎と心の中でバカにしたことでしょう。
生憎、私はドMなのでバカにされることに快感を感じるタイプではあるのですが、悔しい気持ちも2割くらいはあります...
言われっぱなしにならないためにDockerを基礎から学び、手始めに、Dockerって何?というところから、Dockerfileからイメージをビルドしてコンテナを起動するまでの流れを記事にまとめました。
Dockerって何?
いろんなサイトや文献をみるとDockerの定義がばらばらで頭が混乱するのですが、コンテナ作成や実行のためのプラットフォーム(管理ツール)であるDocker Engine*としての意味。もしくは以下のツールの総称として使われることが大半です。
- Docker Client(Docker CLI): Dockerコマンドを実行するコマンドラインツール
- Docker Server(Docker Daemon): イメージの作成、コンテナの実行などを行うもの
- Docker Machine: Mac, Windows上でDockerを使えるようにするもの
- Docker Images: コンテナの素となるもの
- Docker Hub: ユーザーが作成したコンテナをアップロードして公開・共有できるサービス
- Docker Compose: 複数のコンテナで構成されるアプリケーションについて、Dockerイメージのビルドや各コンテナの起動・停止などをより簡単に行えるようにするツール
*Docker EngineはホストOS(カーネル)の上にあり、アプリケーション本体とそれを実行するための環境を1つのDockerイメージにまとめたり、Dockerイメージに基づいてコンテナを実行させ、簡単かつ高速にアプリケーションを起動できます。
そもそもコンテナって何?
コンテナは、仮想マシンと同様に、1つのサーバ上で複数のサーバ環境を分離して実行する仮想化の技術です。
仮想マシンにはホストOS上にハイパーバイザーと呼ばれる管理層があり、ハイパーバイザーが提供する仮想的なハードウェアで複数の異なるOS(ゲストOS)を並列に実行します。一方、コンテナは1つのOSの中を複数の区画に分離する技術であり、1つのカーネルの上で複数のOS環境が動きます。そのため、「OSレベルの仮想化」とも呼ばれます。
仮想マシンが「イメージ」をもとにして作成されるように、コンテナにも「コンテナイメージ」というものが必要です。コンテナイメージには、コンテナで実行するアプリケーションの実行形式ファイルや、その実行のために必要なファイル群しか含まれません。このように、コンテナイメージは非常に軽量(数十~数百MB程度)です。GB級の容量の仮想マシンイメージと比べて少ないリソースでのアプリケーション実行が可能となるため、起動が早く、メモリやCPUリソースを余分に使うことがありません。ネットワークでの共有も迅速に行なえます。
出典: What is Dockerコンテナにおけるカーネルの役割
仮想マシンと違ってコンテナではOS(カーネル)が共有されますが、コンテナが仮想マシンのように独立した環境をもつためには、ハードウェア上のリソースもコンテナごとに制限されている必要があります。コンテナが必要以上のリソースを使わないために、カーネルの以下の機能が使われています。
- Namespacing
- Control Groups(cgroups)
NameSpacing
Namespacingはコンテナを1つの仮想マシンのように占有されたシステムとして見せるためのカーネルの機能です。ハードウェア内にセグメントをつくり、プロセスごとにリソースが隔離されます。
プロセスごとに環境を構築することができるため、他のLinux上で同じ環境を再構築することができます。
Control Groups(cgroups)
Dockerでは、コンテナ内からアクセス可能なシステムのリソース(CPUやメモリなど)を制限しています。これを実現させるために、カーネルのControll Groups(cgroups)という機能を使います。
Namespacingではホスト名やPIDなどのリソースを制御しますが、cgroupsはCPUやメモリなどの物理的なリソースを制御します。
改めて、コンテナというのはプロセスごとにリソースが隔離された状態であり、図にすると以下のようになります。
コンテナイメージとは
コンテナを実行するためには、コンテナの素となるイメージが必要となります。
素の中身には以下の2つのものがあります。
- ファイルシステム
- メタ情報
ファイルシステム(FS)
ファイルシステムというのは、コンテナ上のプロセス(実行アプリケーション)が必要とするファイルのことです。
DockerはLinuxカーネルで動作するため、ディレクトリ階層もLinux規格(/
ディレクトリ以下に/etc
/bin
/sbin
/usr
などがある)となります。メタ情報
アプリケーションの実行に必要なデフォルトのコマンドや引数の指定、外に公開するポート番号の情報、ボリューム領域などをまとめてメタ情報と呼びます。
以下の図のように、イメージからFSやメタ情報がコピーされることでコンテナが実行されます。
簡単な動作確認
Dockerとコンテナについてわかってきたので、Dockerを導入して試しにコンテナを起動してみます。
Docker Desktopの導入
DockerはLinuxカーネル上で動くので、WindowsやMacのPCだとそのままでは動きません。そのため、Linux環境を簡単に構築できるDocker Desktop (for Windows or Mac)をインストールします。インストール後に起動して、"Docker Desktop is running"となっていれば大丈夫です。
docker version
でバージョン情報を調べてみると、確かにOS/Arch:linux/amd64
となっています。(base) [20:52:08] → docker version ~ Client: Docker Engine - Community Cloud integration: 1.0.4 Version: 20.10.2 API version: 1.41 Go version: go1.13.15 Git commit: 2291f61 Built: Mon Dec 28 16:12:42 2020 OS/Arch: darwin/amd64 Context: default Experimental: true Server: Docker Engine - Community Engine: Version: 20.10.2 API version: 1.41 (minimum version 1.12) Go version: go1.13.15 Git commit: 8891c58 Built: Mon Dec 28 16:15:23 2020 OS/Arch: linux/amd64 Experimental: false containerd: Version: v1.4.3 GitCommit: 269548fa27e0089a8b8278fc4fc781d7f65a939b runc: Version: 1.0.0-rc92 GitCommit: ff819c7e9184c13b7c2607fe6c30ae19403a7aff docker-init: Version: 0.19.0 GitCommit: de40ad0イメージからコンテナを起動
docker run [image]
でイメージからコンテナを作成して起動することができます。
hello world
イメージで試しにコマンドを実行してみます。(base) [21:14:40] → docker run hello-world ~ Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. (amd64) 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash Share images, automate workflows, and more with a free Docker ID: https://hub.docker.com/ For more examples and ideas, visit: https://docs.docker.com/get-started/
docker run [image]
を実行すると、docker serverはイメージがローカルのイメージキャッシュ内にあるかどうかをまず確かめます。キャッシュ内にイメージがなければDocker Hubの中を探し、ローカルにイメージを読み込みます。dockerコマンドをいろいろ実行してみる
docker run [image]
イメージからコンテナを作成して起動します。
コンテナの作成はdocker create [image]
、起動はdocker start -a [container id]
で個別に行うことができ、これらの組み合わせがdocker run [image]
となります。docker run [image] [Linuxコマンド]
コンテナ作成起動後にLinuxコマンドを実行することができます。
例えば、ls
コマンドで出力される結果はコンテナ内のディレクトリ構成となります。(base) [21:25:09] → docker run busybox ls ~ bin dev etc home proc root sys tmp usr vardocker ps
起動中のコンテナを全て表示します。
(base) [21:32:27] → docker ps ~ CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 66eaeff67b15 prismagraphql/prisma:1.12 "/bin/sh -c /app/sta…" 6 weeks ago Up 6 weeks 0.0.0.0:4466->4466/tcp prisma_prisma_1 1cb282826d22 complex_nginx "/docker-entrypoint.…" 3 months ago Restarting (1) 14 seconds ago complex_nginx_1 8eac3688a342 visits_node-app "docker-entrypoint.s…" 3 months ago Up Less than a second 0.0.0.0:4001->8081/tcp visits_node-app_1docker ps --all
今までに作成したコンテナを全て表示します。
(base) [21:33:16] → docker ps --all ~ CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 7fc44dbef90d busybox "ls -a" 5 minutes ago Exited (0) 5 minutes ago lucid_raman 86d2d24c54cb busybox "ls" 8 minutes ago Exited (0) 7 minutes ago ...docker system prune
今まで作成したコンテナを全削除します。
docker logs [container id]
コンテナが起動されたときのログを出力します。
docker stop [container id]
起動中のコンテナを停止します。
docker kill [container id]
コンテナを強制停止します。
docker exec -it [container id] [command]
コンテナに追加のプロセスを実行させることができます。ターミナルへのアクセスなどを行います。
例えば、
docker run redis
でredis-serverをコンテナに構築し、redis-serverを操作したくなったとします。そんなときに、docker exec -it [container id] redis-cli
を実行することで、ターミナルからredis-cliのコマンドをうてるようになります。
-i
でredis-cliの標準入力と接続し、-t
で標準出力と接続することができます。
docker exec -it [container id] sh
でコンテナのシェルに接続し、Linuxコマンドがうてるようになります。
また、docker run -it [image] sh
でコンテナの作成起動と同時にコマンドがうてるようになります。Dockerイメージを作成してコンテナを起動してみる
コンテナの素となるDockerイメージは、以下の順序で作られます。
- Dockerfileの作成(Docker Serverへの命令内容を記述)
- イメージのビルド(
docker build .
の実行)Dockerfileの作成
Dockerfileにも記述の順序があります。
- ベースイメージの指定
- 追加プログラムをインストールするためのコマンドを実行
- コンテナプロセスの起動コマンドの指定
例えば、redisイメージ用のDockerファイルは以下のように記述します。
# Use an existing docker image as a base FROM alpine # Download and install a dependency RUN apk add --update redis # Tell the image what to do then it starts # as a container CMD ["redis-server"]*Alpine: Linuxのディストリビューション(Linuxカーネルとその他ソフトウェア群を1つにまとめ、容易にインストール・利用できるようにしたもの)
*apk: Alpineのパッケージマネージャ
*redis: インメモリデータベースDockerfileの中身は、
FROM
,RUN
,CMD
のようなDocker Serverへの命令内容に引数を付加するような構成になっています。
イメージのビルド
docker build .
でDockerfileからコンテナイメージを作成(ビルド)します。最後の.
ではDockerfileのあるディレクトリを指定しています。今回はカレントディレクトリに置いてあるので.
のみとしています。以下がビルドの流れです。
1. コンテナが起動し
apk add --update redis
でredis関連のプログラムをインストールAlpineイメージのファイルシステム(FS)スナップショットがコンテナ内のディレクトリにコピーされコンテナが起動します。その後に
apk add --update redis
でredis関連のプログラムがインストールされます。
2. コンテナが停止し新しいイメージAが作られる
redisがインストールされたファイルシステムのスナップショットがつくられ、コンテナは停止します。コンテナが停止した後に、FSスナップショットから新しいイメージAがつくられます。
3. 再度起動したコンテナに起動時のコマンド
redis-server
を設定する4. コンテナが停止し起動コマンドが設定された最終的なイメージBが作られる
redis関連プログラムとコンテナ起動時のコマンドが設定された最終的なイメージがこれで完成します。
完成したイメージからコンテナを作成・起動する
docker run [container id]
でイメージからコンテナの作成と起動を行うことができます。しかし、この方法だとイメージをビルドしたときにcontainer idを控えておかなければなりません。そんなとき、ビルド時に
docker build -t [タグ名] .
とすることでイメージにタグを付けることができ、docker run [タグ名]
でコンテナを実行することができます。
タグ名としては、[DockerID]/[Project名]:Versionとつけるのが一般的です。以上がDockerfileの作成からコンテナを起動するまでの流れです。
ちなみに、以下のコマンドを実行すれば、Dockerfileを使わずにこれまでの流れを実施することができます。
docker run -it alpine sh
apk add --update redis
docker commit -c 'CMD['redis-server']' [id]
docker run ~
参考文献
おわりに
記事でアウトプットしたことでコンテナとDockerの理解が深まりました。次は実際のプロジェクトにDockerを導入したときの記事を書きたいと思います。
- 投稿日:2021-03-05T23:13:27+09:00
コンテナ未経験なのでDockerを基礎から学んでみた
こんにちは、業務でDockerなど使ったことがないコンテナ童貞のすずきです。
この時点で、この記事を読んだ9割の現役エンジニアの方々は、私のことをコンテナも知らないレガシー雑魚野郎と心の中でバカにしたことでしょう。
生憎、私はドMなのでバカにされることに快感を感じるタイプではあるのですが、悔しい気持ちも2割くらいはあります...
言われっぱなしにならないためにDockerを基礎から学び、手始めに、Dockerって何?というところから、Dockerfileからイメージをビルドしてコンテナを起動するまでの流れを記事にまとめました。
Dockerって何?
いろんなサイトや文献をみるとDockerの定義がばらばらで頭が混乱するのですが、コンテナ作成や実行のためのプラットフォーム(管理ツール)であるDocker Engine*としての意味。もしくは以下のツールの総称として使われることが大半です。
- Docker Client(Docker CLI): Dockerコマンドを実行するコマンドラインツール
- Docker Server(Docker Daemon): イメージの作成、コンテナの実行などを行うもの
- Docker Machine: Mac, Windows上でDockerを使えるようにするもの
- Docker Images: コンテナの素となるもの
- Docker Hub: ユーザーが作成したコンテナをアップロードして公開・共有できるサービス
- Docker Compose: 複数のコンテナで構成されるアプリケーションについて、Dockerイメージのビルドや各コンテナの起動・停止などをより簡単に行えるようにするツール
*Docker EngineはホストOS(カーネル)の上にあり、アプリケーション本体とそれを実行するための環境を1つのDockerイメージにまとめたり、Dockerイメージに基づいてコンテナを実行させ、簡単かつ高速にアプリケーションを起動できます。
そもそもコンテナって何?
コンテナは、仮想マシンと同様に、1つのサーバ上で複数のサーバ環境を分離して実行する仮想化の技術です。
仮想マシンにはホストOS上にハイパーバイザーと呼ばれる管理層があり、ハイパーバイザーが提供する仮想的なハードウェアで複数の異なるOS(ゲストOS)を並列に実行します。一方、コンテナは1つのOSの中を複数の区画に分離する技術であり、1つのカーネルの上で複数のOS環境が動きます。そのため、「OSレベルの仮想化」とも呼ばれます。
仮想マシンが「イメージ」をもとにして作成されるように、コンテナにも「コンテナイメージ」というものが必要です。コンテナイメージには、コンテナで実行するアプリケーションの実行形式ファイルや、その実行のために必要なファイル群しか含まれません。このように、コンテナイメージは非常に軽量(数十~数百MB程度)です。GB級の容量の仮想マシンイメージと比べて少ないリソースでのアプリケーション実行が可能となるため、起動が早く、メモリやCPUリソースを余分に使うことがありません。ネットワークでの共有も迅速に行なえます。
出典: What is Dockerコンテナにおけるカーネルの役割
仮想マシンと違ってコンテナではOS(カーネル)が共有されますが、コンテナが仮想マシンのように独立した環境をもつためには、ハードウェア上のリソースもコンテナごとに制限されている必要があります。コンテナが必要以上のリソースを使わないために、カーネルの以下の機能が使われています。
- Namespacing
- Control Groups(cgroups)
NameSpacing
Namespacingはコンテナを1つの仮想マシンのように占有されたシステムとして見せるためのカーネルの機能です。ハードウェア内にセグメントをつくり、プロセスごとにリソースが隔離されます。
プロセスごとに環境を構築することができるため、他のLinux上で同じ環境を再構築することができます。
Control Groups(cgroups)
Dockerでは、コンテナ内からアクセス可能なシステムのリソース(CPUやメモリなど)を制限しています。これを実現させるために、カーネルのControll Groups(cgroups)という機能を使います。
Namespacingではホスト名やPIDなどのリソースを制御しますが、cgroupsはCPUやメモリなどの物理的なリソースを制御します。
改めて、コンテナというのはプロセスごとにリソースが隔離された状態であり、図にすると以下のようになります。
コンテナイメージとは
コンテナを実行するためには、コンテナの素となるイメージが必要となります。
素の中身には以下の2つのものがあります。
- ファイルシステム
- メタ情報
ファイルシステム(FS)
ファイルシステムというのは、コンテナ上のプロセス(実行アプリケーション)が必要とするファイルのことです。
DockerはLinuxカーネルで動作するため、ディレクトリ階層もLinux規格(/
ディレクトリ以下に/etc
/bin
/sbin
/usr
などがある)となります。メタ情報
アプリケーションの実行に必要なデフォルトのコマンドや引数の指定、外に公開するポート番号の情報、ボリューム領域などをまとめてメタ情報と呼びます。
以下の図のように、イメージからFSやメタ情報がコピーされることでコンテナが実行されます。
簡単な動作確認
Dockerとコンテナについてわかってきたので、Dockerを導入して試しにコンテナを起動してみます。
Docker Desktopの導入
DockerはLinuxカーネル上で動くので、WindowsやMacのPCだとそのままでは動きません。そのため、Linux環境を簡単に構築できるDocker Desktop (for Windows or Mac)をインストールします。インストール後に起動して、"Docker Desktop is running"となっていれば大丈夫です。
docker version
でバージョン情報を調べてみると、Client側(Docker CLIでコマンドを実行した側)はdarwin/amd64
で、Server側(Dockerコマンドによる命令を実行する側)はOS/Arch:linux/amd64
となっています。(base) [20:52:08] → docker version ~ Client: Docker Engine - Community Cloud integration: 1.0.4 Version: 20.10.2 API version: 1.41 Go version: go1.13.15 Git commit: 2291f61 Built: Mon Dec 28 16:12:42 2020 OS/Arch: darwin/amd64 Context: default Experimental: true Server: Docker Engine - Community Engine: Version: 20.10.2 API version: 1.41 (minimum version 1.12) Go version: go1.13.15 Git commit: 8891c58 Built: Mon Dec 28 16:15:23 2020 OS/Arch: linux/amd64 Experimental: false containerd: Version: v1.4.3 GitCommit: 269548fa27e0089a8b8278fc4fc781d7f65a939b runc: Version: 1.0.0-rc92 GitCommit: ff819c7e9184c13b7c2607fe6c30ae19403a7aff docker-init: Version: 0.19.0 GitCommit: de40ad0イメージからコンテナを起動
docker run [image]
でイメージからコンテナを作成して起動することができます。
hello world
イメージで試しにコマンドを実行してみます。(base) [21:14:40] → docker run hello-world ~ Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. (amd64) 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash Share images, automate workflows, and more with a free Docker ID: https://hub.docker.com/ For more examples and ideas, visit: https://docs.docker.com/get-started/
docker run [image]
を実行すると、docker serverはイメージがローカルのイメージキャッシュ内にあるかどうかをまず確かめます。キャッシュ内にイメージがなければDocker Hubの中を探し、ローカルにイメージを読み込みます。dockerコマンドをいろいろ実行してみる
docker run [image]
イメージからコンテナを作成して起動します。
コンテナの作成はdocker create [image]
、起動はdocker start -a [container id]
で個別に行うことができ、これらの組み合わせがdocker run [image]
となります。docker run [image] [Linuxコマンド]
コンテナ作成起動後にLinuxコマンドを実行することができます。
例えば、ls
コマンドで出力される結果はコンテナ内のディレクトリ構成となります。(base) [21:25:09] → docker run busybox ls ~ bin dev etc home proc root sys tmp usr vardocker ps
起動中のコンテナを全て表示します。
(base) [21:32:27] → docker ps ~ CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 66eaeff67b15 prismagraphql/prisma:1.12 "/bin/sh -c /app/sta…" 6 weeks ago Up 6 weeks 0.0.0.0:4466->4466/tcp prisma_prisma_1 1cb282826d22 complex_nginx "/docker-entrypoint.…" 3 months ago Restarting (1) 14 seconds ago complex_nginx_1 8eac3688a342 visits_node-app "docker-entrypoint.s…" 3 months ago Up Less than a second 0.0.0.0:4001->8081/tcp visits_node-app_1docker ps --all
今までに作成したコンテナを全て表示します。
(base) [21:33:16] → docker ps --all ~ CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 7fc44dbef90d busybox "ls -a" 5 minutes ago Exited (0) 5 minutes ago lucid_raman 86d2d24c54cb busybox "ls" 8 minutes ago Exited (0) 7 minutes ago ...docker system prune
今まで作成したコンテナを全削除します。
docker logs [container id]
コンテナが起動されたときのログを出力します。
docker stop [container id]
起動中のコンテナを停止します。
docker kill [container id]
コンテナを強制停止します。
docker exec -it [container id] [command]
コンテナに追加のプロセスを実行させることができます。ターミナルへのアクセスなどを行います。
例えば、
docker run redis
でredis-serverをコンテナに構築し、redis-serverを操作したくなったとします。そんなときに、docker exec -it [container id] redis-cli
を実行することで、ターミナルからredis-cliのコマンドをうてるようになります。
-i
でredis-cliの標準入力と接続し、-t
で標準出力と接続することができます。
docker exec -it [container id] sh
でコンテナのシェルに接続し、Linuxコマンドがうてるようになります。
また、docker run -it [image] sh
でコンテナの作成起動と同時にコマンドがうてるようになります。Dockerイメージを作成してコンテナを起動してみる
コンテナの素となるDockerイメージは、以下の順序で作られます。
- Dockerfileの作成(Docker Serverへの命令内容を記述)
- イメージのビルド(
docker build .
の実行)Dockerfileの作成
Dockerfileにも記述の順序があります。
- ベースイメージの指定
- 追加プログラムをインストールするためのコマンドを実行
- コンテナプロセスの起動コマンドの指定
例えば、redisイメージ用のDockerファイルは以下のように記述します。
# Use an existing docker image as a base FROM alpine # Download and install a dependency RUN apk add --update redis # Tell the image what to do then it starts # as a container CMD ["redis-server"]*Alpine: Linuxのディストリビューション(Linuxカーネルとその他ソフトウェア群を1つにまとめ、容易にインストール・利用できるようにしたもの)
*apk: Alpineのパッケージマネージャ
*redis: インメモリデータベースDockerfileの中身は、
FROM
,RUN
,CMD
のようなDocker Serverへの命令内容に引数を付加するような構成になっています。
イメージのビルド
docker build .
でDockerfileからコンテナイメージを作成(ビルド)します。最後の.
ではDockerfileのあるディレクトリを指定しています。今回はカレントディレクトリに置いてあるので.
のみとしています。以下がビルドの流れです。
1. コンテナが起動し
apk add --update redis
でredis関連のプログラムをインストールAlpineイメージのファイルシステム(FS)スナップショットがコンテナ内のディレクトリにコピーされコンテナが起動します。その後に
apk add --update redis
でredis関連のプログラムがインストールされます。
2. コンテナが停止し新しいイメージAが作られる
redisがインストールされたファイルシステムのスナップショットがつくられ、コンテナは停止します。コンテナが停止した後に、FSスナップショットから新しいイメージAがつくられます。
3. 再度起動したコンテナに起動時のコマンド
redis-server
を設定する4. コンテナが停止し起動コマンドが設定された最終的なイメージBが作られる
redis関連プログラムとコンテナ起動時のコマンドが設定された最終的なイメージがこれで完成します。
完成したイメージからコンテナを作成・起動する
docker run [container id]
でイメージからコンテナの作成と起動を行うことができます。しかし、この方法だとイメージをビルドしたときにcontainer idを控えておかなければなりません。そんなとき、ビルド時に
docker build -t [タグ名] .
とすることでイメージにタグを付けることができ、docker run [タグ名]
でコンテナを実行することができます。
タグ名としては、[DockerID]/[Project名]:Versionとつけるのが一般的です。以上がDockerfileの作成からコンテナを起動するまでの流れです。
ちなみに、以下のコマンドを実行すれば、Dockerfileを使わずにこれまでの流れを実施することができます。
docker run -it alpine sh
apk add --update redis
docker commit -c 'CMD['redis-server']' [id]
docker run ~
おわりに
記事でアウトプットしたことでコンテナとDockerの理解が深まりました。次は実際のプロジェクトにDockerを導入したときの記事を書きたいと思います。
参考資料
- 投稿日:2021-03-05T21:58:59+09:00
初学者がDockerで、Django+gunicorn+nginx+PostgreSQLで環境を構築する
Dockerfileを作成
DockerfileFROM python:3.7 RUN apt-get update && apt-get install -y \ nano WORKDIR /code COPY requirements.txt /code/ RUN pip install -r requirements.txt RUN mkdir -p /var/run/gunicorn #CMD ["gunicorn", "conf.wsgi", "--bind=unix:/var/run/gunicorn/gunicorn.sock"]requirements.txtを作成
requirements.txtDjango psycopg2 gunicorndocker-compose.ymlを作成
docker-compose.ymlversion: '3' volumes: gunicorn: driver: local dbdata: services: web: build: context: . dockerfile: Dockerfile container_name: django ports: - '8000:8000' volumes: - './web:/code' - './web/static:/static' - gunicorn:/var/run/gunicorn tty: true stdin_open: true nginx: image: nginx container_name: nginx ports: - '80:80' volumes: - './nginx/conf:/etc/nginx/conf.d' - './web/static:/static' - gunicorn:/var/run/gunicorn depends_on: - web db: image: postgres container_name: db ports: - "5432:5432" volumes: - "dbdata:/var/lib/postgresql/data" environment: - 'POSTGRES_DB=postgres' - 'POSTGRES_USER=postgres' - 'POSTGRES_PASSWORD=password' - 'POSTGRES_HOST_AUTH_METHOD=trust'ディレクトリを作る
構成. ├── Dockerifle ├── requirements.txt ├── docker-compose.yml ├── nginx │ └── conf.d # gunicornの設定ファイルを格納するため └── web # djangoプロジェクトを格納するためgunicornの設定ファイルを作成
構成. ├── docker-compose.yml ├── Dockerifle ├── requirements.txt ├── nginx │ └── conf │ └── gunicorn.conf # コレを作成 └── webgunicorn.confの中身はこのような感じです。
gunicorn.confupstream gunicorn-django { server unix:///var/run/gunicorn/gunicorn.sock; } server { listen 80; server_name localhost; location /static { alias /static/; } location / { try_files $uri @gunicorn; } location @gunicorn { proxy_pass http://gunicorn-django; } }docker-composeでイメージをビルドし、コンテナを起動する
$ docker-compose up -d$ docker-compose ps でコンテナが二つともUpになっていることを確認します。
djangoプロジェクトを作成
まずはdjangoコンテナに入ります。
$ docker-compose exec web bashdjangoプロジェクトを作成します。
$ django-admin startproject conf .settings.pyを変更
先ほど作成したdjangoプロジェクト内にあるsettings.pyのALLOWED_HOSTSを変更します。とりあえずどんなサーバーアドレスからのアクセスも受理することにしますが、必要に応じて変更した方が良いような気がします。。。
settings.pyALLOWED_HOSTS = ['*']exitでコンテナから抜けます。 そして、一旦、コンテナをダウンさせます。stopでも良いかもしれません。
$ docker-compose down次にDockerfileに追記します。
Dockerfile# 末尾に追加 CMD ["gunicorn", "conf.wsgi", "--bind=unix:/var/run/gunicorn/gunicorn.sock"]再びDockerをupさせます。
$ docker-compose up --build -d$ docker-compose psでコンテナがUpになっていることを確認したら、ブラウザからlocalhost:80にアクセスし、ロケットが飛び立っていることを確認します。
- 投稿日:2021-03-05T21:58:59+09:00
初学者がDockerを使ってDjango+gunicorn+nginx+PostgreSQLの環境を構築する
Dockerfileを作成
DockerfileFROM python:3.7 RUN apt-get update && apt-get install -y \ nano WORKDIR /code COPY requirements.txt /code/ RUN pip install -r requirements.txt RUN mkdir -p /var/run/gunicorn #CMD ["gunicorn", "conf.wsgi", "--bind=unix:/var/run/gunicorn/gunicorn.sock"]requirements.txtを作成
requirements.txtDjango psycopg2 gunicorndocker-compose.ymlを作成
docker-compose.ymlversion: '3' volumes: gunicorn: driver: local dbdata: services: web: build: context: . dockerfile: Dockerfile container_name: django ports: - '8000:8000' volumes: - './web:/code' - './web/static:/static' - gunicorn:/var/run/gunicorn tty: true stdin_open: true nginx: image: nginx container_name: nginx ports: - '80:80' volumes: - './nginx/conf:/etc/nginx/conf.d' - './web/static:/static' - gunicorn:/var/run/gunicorn depends_on: - web db: image: postgres container_name: db ports: - "5432:5432" volumes: - "dbdata:/var/lib/postgresql/data" environment: - 'POSTGRES_DB=postgres' - 'POSTGRES_USER=postgres' - 'POSTGRES_PASSWORD=password' - 'POSTGRES_HOST_AUTH_METHOD=trust'ディレクトリを作る
構成. ├── Dockerifle ├── requirements.txt ├── docker-compose.yml ├── nginx │ └── conf.d # gunicornの設定ファイルを格納するため └── web # djangoプロジェクトを格納するためgunicornの設定ファイルを作成
構成. ├── docker-compose.yml ├── Dockerifle ├── requirements.txt ├── nginx │ └── conf │ └── gunicorn.conf # コレを作成 └── webgunicorn.confの中身はこのような感じです。
gunicorn.confupstream gunicorn-django { server unix:///var/run/gunicorn/gunicorn.sock; } server { listen 80; server_name localhost; location /static { alias /static/; } location / { try_files $uri @gunicorn; } location @gunicorn { proxy_pass http://gunicorn-django; } }docker-composeでイメージをビルドし、コンテナを起動する
$ docker-compose up -d$ docker-compose ps でコンテナが全てUpになっていることを確認します。
djangoプロジェクトを作成
まずはdjangoコンテナに入ります。
$ docker-compose exec web bashdjangoプロジェクトを作成します。
$ django-admin startproject conf .settings.pyを変更
先ほど作成したdjangoプロジェクト内にあるsettings.pyのALLOWED_HOSTSを変更します。とりあえずどんなサーバーアドレスからのアクセスも受理することにしますが、必要に応じて変更した方が良いような気がします。。。
settings.pyALLOWED_HOSTS = ['*']exitでコンテナから抜けます。 そして、一旦、コンテナをダウンさせます。stopでも良いかもしれません。
$ docker-compose down次にDockerfileに追記します。
Dockerfile# 末尾に追加 CMD ["gunicorn", "conf.wsgi", "--bind=unix:/var/run/gunicorn/gunicorn.sock"]再びDockerをupさせます。
$ docker-compose up --build -d$ docker-compose psでコンテナがUpになっていることを確認したら、ブラウザからlocalhost:80にアクセスし、ロケットが飛び立っていることを確認します。
- 投稿日:2021-03-05T21:44:32+09:00
Docker buildできない【echoコマンド】
前提
ホストOS:Windows(touchコマンドが使えない)
起こったこと
下記イメージを作ろうとしたところ…
DockerfileFROM ubuntu:latest RUN touch hoge$docker build .エラーがでました。
failed to solve with frontend dockerfile.v0: failed to create LLB definition: dockerfile parse error line 1: unknown instruction: ��F R O M原因
Dockerfileのファイルを作成する際に、
WindowsOSのためtouchコマンドが使えず、
新規ファイル作成の際、echoコマンドを使っていましたが、
その使い方がNGでした。具体的には下記がNG
echo "" > Dockerfile理屈は
①Dockerfileに空の文字列を挿入する。
②Dockerfileがないので空の新規ファイルが作られる。なんですが、echoコマンドで出力すると、デフォルトで出力文字の最後が改行されるようで
それが原因なのか微妙(入力して修正するので)ですが、
-nオプションをつけると解決しました。echo -n > Dockerfiledocker build .原因曖昧であれなのですが、、
とにかく、echo "" > Dockerfileという書き方は使わないようにします。
- 投稿日:2021-03-05T21:44:32+09:00
Docker buildできない際の原因【echoコマンド】
前提
ホストOS:Windows(touchコマンドが使えない)
起こったこと
下記イメージを作ろうとしたところ…
DockerfileFROM ubuntu:latest RUN touch hoge$docker build .エラーがでました。
failed to solve with frontend dockerfile.v0: failed to create LLB definition: dockerfile parse error line 1: unknown instruction: ��F R O M原因
Dockerfileのファイルを作成する際に、
WindowsOSのためtouchコマンドが使えず、
新規ファイル作成の際、echoコマンドを使っていましたが、
その使い方がNGでした。具体的には下記がNG
echo "" > Dockerfile理屈は
①Dockerfileに空の文字列を挿入する。
②Dockerfileがないので空の新規ファイルが作られる。なんですが、echoコマンドで出力すると、デフォルトで出力文字の最後が改行されるようで
それが原因なのか微妙(入力して修正するので)ですが、
-nオプションをつけると解決しました。echo -n > Dockerfiledocker build .原因曖昧であれなのですが、、
とにかく、echo "" > Dockerfileという書き方は使わないようにします。
- 投稿日:2021-03-05T19:55:51+09:00
開発環境のLaravelアプリケーションにphp-graph-sdkを使用してFacebookログイン機能を組み込む時に詰まったこと
LaravelでFacebookログインボタンを設置して、AccessTokenを取得する処理を書きたい
とりあえず以下のライブラリを使うことに。
Dockerfileとdocker-compose.ymlを使用して開発環境を作成。
http://localhost:3000/facebook/login
でボタンを表示するようにしました。
以下にコードを記しますが、Facebookのドキュメントのまんまです。
Controllers/FacebookController.php
の一部//ログインボタンを表示する処理 public function login() { $fb = new Facebook\Facebook([ 'app_id' => '{app-id}', 'app_secret' => '{app-secret}', 'default_graph_version' => 'v2.10', ]); $helper = $fb->getRedirectLoginHelper(); $permissions = ['email']; // Optional permissions //callback先はhttp://localhost:3000/facebook/callbackに $loginUrl = $helper->getLoginUrl('http://localhost:3000/facebook/callback', $permissions); echo '<a href="' . $loginUrl . '">Log in with Facebook!</a>'; }//callback先でAccessTokenを表示する処理 public function callback() { $fb = new Facebook\Facebook([ 'app_id' => '{app-id}', 'app_secret' => '{app-secret}', 'default_graph_version' => 'v2.10', ]); $helper = $fb->getRedirectLoginHelper(); try { //後々ここでエラー発生!!!!!!!!! $accessToken = $helper->getAccessToken(); } catch(Facebook\Exception\ResponseException $e) { echo 'Graph returned an error: ' . $e->getMessage(); exit; } catch(Facebook\Exception\SDKException $e) { echo 'Facebook SDK returned an error: ' . $e->getMessage(); exit; } $oAuth2Client = $fb->getOAuth2Client(); $tokenMetadata = $oAuth2Client->debugToken($accessToken); $tokenMetadata->validateAppId($config['app_id']); $tokenMetadata->validateExpiration(); if (! $accessToken->isLongLived()) { try { $accessToken = $oAuth2Client->getLongLivedAccessToken($accessToken); } catch (Facebook\Exception\SDKException $e) { echo "<p>Error getting long-lived access token: " . $e->getMessage() . "</p>\n\n"; exit; } echo '<h3>AccessToken</h3>'; var_dump($accessToken->getValue()); } }意気揚々とログインを実行するとエラーが発生...
エラー内容はこちらです。
Graph returned an error: Please make sure your redirect_uri is identical to the one you used in the OAuth dialog requestGoogleログインなどでもよくある、APIの管理画面でリダイレクトURLを設定忘れだと思い管理画面へアクセス。
ドキュメント読むとなんとFacebookログインのリダイレクト先はhttps必須とのこと..
2018年10月6日から、すべてのアプリでHTTPSの使用が必須になります。
しかし!!
管理画面を見てみると以下の記述がありました!
「http://localhost のリダイレクトは開発モードでのみ自動的に許可され、ここに追加する必要はありません」
開発モードの場合はhttp://localhost からもログインできる!
Facebookはリダイレクト先のhttps強制。
しかし、localhostは別とのこと。良かった!!開発モードについてはこちらを参照。
ざっくりまとめると以下のようなことが書かれている。
アプリのモードは、誰がアプリを使用できるかを決定します。
開発モードのアプリは、アプリ上の役割を持つアプリユーザー、またはアプリを主張しているビジネスの役割を持つアプリユーザーのみが使用できます。ってことは自分のアプリ開発モードになっていない説..?
調べたところ..
自分のはビジネスアプリとして作成したてのアプリだったので確かに開発モードになっていました。
厳密に言うと、ビジネスアプリで作成したアプリには開発モードという概念は無いそうですが、一般に公開をしていない限り開発モードと同じらしい。新しく作成されたアプリはすべて開発モードでスタートし、アプリの開発が完了するまでライブモードに切り替えないでください。
ビジネスアプリにはアプリモードがなく、同じ機能を提供するアクセスレベルに依存していることに注意してください。ということはなぜリダイレクトエラー出るの??解決法
エラーが出ている箇所は上記のFacebookController.phpの
callback()
内の以下の一文でした。
$accessToken = $helper->getAccessToken();
結論ですが、以下のようにcallback先のURLを明示的に渡してあげると解決しました。
$accessToken = $helper->getAccessToken(url(/facebook/callback)'); or $accessToken = $helper->getAccessToken(http://localhost:3000/facebook/callback);なぜこの方法で解決できた??
ライブラリ内の
getAccessToken()
を覗いてみます。こちらの行に関数が書かれています。
getAccessToken()の引数はnullを渡しても、ログインボタンに埋め込まれているURLからリダイレクトして、現在地のURLをよしなに取得してくれるはず。
//ログインボタンの所はこう書きました $loginUrl = $helper->getLoginUrl('http://localhost:3000/facebook/callback', $permissions); echo '<a href="' . $loginUrl . '">Log in with Facebook!</a>';//ライブラリの中身抜粋 (現在地からURLを取得してくれる処理) $redirectUrl = $redirectUrl ?: $this->urlDetectionHandler->getCurrentUrl(); $redirectUrl = FacebookUrlManipulator::removeParamsFromUrl($redirectUrl, ['code', 'enforce_https', 'state']); echo $redirectUrlこの関数を手元で実行してみると....
以下が返ってきました。ポート番号の:3000が消えてる...これだとredirectUrlが確かに一致していません。理想は以下のURLを返したい
さらに探っていくと原因が分かりました。
ポート番号を取得する処理はこんな感じで書かれていました。$port = isset($_SERVER["HTTP_X_FORWARDED_PORT"]) ? $_SERVER["HTTP_X_FORWARDED_PORT"] : '';これを実行すると、
''
が返ってきました。
$_SERVER["HTTP_X_FORWARDED_PORT"]
に値が入っていないようです。HTTP_X_FORWARDED_PORTがよく分かっていないですが、、調べてみると
If you are serving from behind a proxy server, you will almost certainly save time by looking at what these $_SERVER variables do on your machine behind the proxy.
日本語訳: プロキシサーバの後ろからサービスを提供している場合、これらの $_SERVER 変数がプロキシの後ろのマシンで何をしているかを見れば、ほぼ確実に時間を節約することができます。
X-Forwarded-Port リクエストヘッダーは、ロードバランサーへの接続にクライアントが使用した送信先ポートを識別するために役立つそうです。
なるほど、今回はDockerを使っています。ポート番号3000をブラウザのURLの入力欄に入力すると、nginxの80番にポートフォワードするようにしています。プロキシサーバーは使用していないので、
$_SERVER["HTTP_X_FORWARDED_PORT"]
に値が入っていないのですね。おそらく。
$port = isset($_SERVER["HTTP_X_FORWARDED_PORT"]) ? $_SERVER["HTTP_X_FORWARDED_PORT"] : $_SERVER["HTTP_HOST"];
こう書くと"localhost:3000"を返してくれますが..
どうするのがベストなのだろう??ということでプロキシサーバーを使用せずに、このライブラリを使用したFacebookログイン機能で詰まるかもしれません。
そんな場合は以下のように書いてみてください!
$accessToken = $helper->getAccessToken(url(/facebook/callback)'); or $accessToken = $helper->getAccessToken(http://localhost:3000/facebook/callback);以上です。
コメントや指摘等お待ちしております。
- 投稿日:2021-03-05T17:20:16+09:00
Dockerによる開発環境を立ち上げるまで【Rails + Nginx + Unicorn + MySQL】
Dockerを導入し、コンテナを立ち上げVSCodeで開発を行うところまで環境構築ができました。
備忘として導入した流れを簡単にまとめておきたいと思います。インストール
Docker公式サイトからDocker Desctopをダウンロード。
以下の記事を参考にしてインストールしました。フォルダ構成
Dockerfileは記事によって配置場所が異なりますが、個人的にはこの構成が一番綺麗にまとまってると思いました。
Dockerfileやdocker-compose.yml、それにNginxやUnicornの設定ファイルは自動生成されないので自分で作ります。app ├ config │ ├ database.yml │ └ unicorn_development.conf.rb ├ docker │ ├ web │ │ └ Dockerfile │ └ nginx │ ├ Dockerfile │ └ revorite.conf └ docker-compose.ymlDocker関連ファイルの記述
以下記事を参考にさせていただきました。
参考記事:DockerでNginx+unicorn+rails+Mysqlの開発環境を作ってみたdocker/web/Dockerfile
FROM ruby:2.7.1 # dockerizeパッケージダウンロード用環境変数 ENV DOCKERIZE_VERSION v0.6.1 # パッケージの取得 RUN apt-get update && \ apt-get install -y --no-install-recommends\ nodejs \ vim \ mariadb-client \ build-essential \ wget \ && wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz \ && tar -C /usr/local/bin -xzvf dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz \ && rm dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* WORKDIR /app COPY Gemfile /app/Gemfile COPY Gemfile.lock /app/Gemfile.lock RUN echo "alias cp='cp -i'" >> /root/.bashrc RUN echo "alias mv='mv -i'" >> /root/.bashrc RUN echo "alias rm='rm -i'" >> /root/.bashrc RUN echo "alias la='ls -al'" >> /root/.bashrc RUN echo "alias ll='ls -l'" >> /root/.bashrc RUN gem install bundler RUN bundle install COPY . /appdocker/nginx/Dockerfile
FROM nginx:stable # デフォルトのNginxの設定ファイルを削除し、作成しておいた設定ファイルをコピー RUN rm -f /etc/nginx/conf.d/* COPY ./docker/nginx/revorite.conf /etc/nginx/conf.d/revorite.conf RUN echo "alias cp='cp -i'" >> /root/.bashrc RUN echo "alias mv='mv -i'" >> /root/.bashrc RUN echo "alias rm='rm -i'" >> /root/.bashrc RUN echo "alias la='ls -al'" >> /root/.bashrc RUN echo "alias ll='ls -l'" >> /root/.bashrc # -c以降の設定ファイルを指定して起動 daemon offでフォアグラウンドで起動 CMD /usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.confdocker/nginx/revorite.conf (Nginx設定ファイル)
docker/nginx/revorite.conf# log directory error_log /var/log/nginx.error.log; access_log /var/log/nginx.access.log; # max body size client_max_body_size 2G; upstream unicorn { # for UNIX domain socket setups server unix:/app/tmp/sockets/.unicorn.sock fail_timeout=0; } server { listen 80; server_name localhost; # nginx so increasing this is generally safe... keepalive_timeout 5; # path for static files root /app/public; location @unicorn { # HTTP headers proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_redirect off; proxy_pass http://unicorn; } location / { try_files $uri/index.html $uri.html $uri @unicorn; include /etc/nginx/mime.types; } location ~ ^/assets/(.*) { alias /app/public/assets/$1; } # Rails error pages error_page 500 502 503 504 /500.html; location = /500.html { root /app/public; } }docker-compose.yml
docker-compose.ymlversion: '3' services: web: build: context: . dockerfile: ./docker/web/Dockerfile # dockerizeを使い、DBの起動を待ってからUnicornを起動する。 command: dockerize -wait tcp://db:3306 -timeout 20s bundle exec unicorn -p 3000 -c /app/config/unicorn_development.conf.rb environment: TZ: Asia/Tokyo tty: true # binding.pryを利用可能にするための2行 stdin_open: true # binding.pryを利用可能にするための2行 depends_on: - db ports: - "3000:3000" volumes: - .:/app:cached # ソケット通信用ファイルをnginxコンテナと共有 - tmp-data:/app/tmp/sockets # アセットファイルをnginxと共有 - public-data:/app/public db: image: mysql:5.7 command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci ports: - "4306:3306" environment: MYSQL_DATABASE: revorite_development MYSQL_ROOT_PASSWORD: password # dbのデータを永続化しておく volumes: - mysql-data:/var/lib/mysql nginx: build: context: . dockerfile: ./docker/nginx/Dockerfile ports: - 80:80 restart: always #明示的にstopさせるまでリスタートする。(失敗するたび遅延あり) volumes: - tmp-data:/app/tmp/sockets - public-data:/app/public depends_on: - web volumes: public-data: tmp-data: mysql-data:config/database.yml
database.ymldefault: &default adapter: mysql2 encoding: utf8 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> development: <<: *default host: db username: root password: password database: revorite_developmentconfig/unicorn_development.conf.rb
config/unicorn_development.conf.rb# set lets $worker = 2 $timeout = 30 $app_dir = "/app" $listen = File.expand_path 'tmp/sockets/.unicorn.sock', $app_dir $pid = File.expand_path 'tmp/pids/unicorn.pid', $app_dir $std_log = File.expand_path 'log/unicorn.log', $app_dir # set config worker_processes $worker working_directory $app_dir stderr_path $std_log stdout_path $std_log timeout $timeout listen $listen pid $pid # loading booster preload_app true # before starting processes before_fork do |server, worker| defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect! old_pid = "#{server.config[:pid]}.oldbin" if old_pid != server.pid begin Process.kill "QUIT", File.read(old_pid).to_i rescue Errno::ENOENT, Errno::ESRCH end end end # after finishing processes after_fork do |server, worker| defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection endコンテナ作成・起動
$ docker-compose build # イメージの作成 $ docker-compose up -d # コンテナの作成・起動詰まった点
他の記事ではあまり語られておらず、自分が詰まった点をいくつか。
Unicornの起動で失敗する
関連ファイルを作り終え、いざ
docker-compose build
とdocker-compose up -d
を叩く。
そしてdocker ps
を叩くと・・・CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 11e605b70c51 revorite_nginx "/docker-entrypoint.…" 21 minutes ago Up 21 minutes 0.0.0.0:80->80/tcp revorite_nginx_1 313d53cbbc27 mysql:5.7 "docker-entrypoint.s…" 21 minutes ago Up 21 minutes 33060/tcp, 0.0.0.0:4306->3306/tcp revorite_db_1あれ?アプリサーバは???
で、docker-compose logs
でログを見てみるとweb_1 | 2021/03/04 11:01:27 Command exited with error: exit status 1
exit status 1
とは一体・・・
exitしたということは一度起動して即落ちた、と読めるので、落ちたコンテナに入ってログも見てみたのですがそれらしいログは出ていない。
(落ちたコンテナに入る方法はこちらを参考にしました)最終的に、
database.yml
にhost: db
の記述が漏れているためだということが判明。一文追加し、無事起動しました。
こんな単純なミスなのですが一日使ってしまったので、Dockerfileとdocker-composeだけを書いて満足しないように注意です。コンテナ内でGitが使えない
GitをインストールしSSH認証もできるようにしたのですが、どうしてもgit pushだけが弾かれてしまうんですよね。(commitまではできる)
git@github.com: Permission denied (publickey). fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists.仕方ないのでgit関連の操作はホスト側で実行しています(ホスト側でコンテナ内のソースコードに対しマウントしている)。git操作もコンテナ内で完結できたらベストだったのですが。
コンテナ内で開発を行う(VSCode: Remote Development)
コンテナ内で開発を行うには、VSCodeでコンテナ内のソースを参照・開発できるRemote Developmentという拡張機能を使います。
参考記事:VS Code Remote Development で Docker 開発環境を利用する前述の起動コマンドで起動できていれば、参考記事の通りに起動するだけで特に問題は起きないはず。
その他補足
docker関連のコマンドは長いので、~/.bashrcにエイリアスを設定すると便利。
またエラーが起きる度にコンテナやイメージの削除コマンドを打つのが大変のため、こちらも設定しておくと快適です。# 例 alias dco='docker-compose' alias docker-purge='docker stop $(docker ps -q) && docker rm $(docker ps -a -q) && docker rmi $(docker images -q -a) -f'改善点や誤りなどありましたらコメントで指摘いただけると幸いです。
- 投稿日:2021-03-05T16:33:08+09:00
Komposeを使ってdocker-compose.ymlからk8sマニフェストファイルを作成する
はじめに
この記事の環境は以下のGitHubにあります。
https://github.com/bocci-farm/docker-railsインストール
% brew install kompose
元になるdocker-composeを作成
versionは"3"や"3.8", "3.9"だと後のkomposeの工程でエラーになったので"3.7"にしています。
docker-compose.ymlversion: "3.7" services: db: image: boccifarm/mysql:8.0.23 build: context: ./docker/db/ environment: MYSQL_ROOT_PASSWORD: password ports: - 3306:3306 - 33060:33060 volumes: - type: volume source: db target: /var/lib/mysql app: image: boccifarm/rails:6.1.3-ruby3.0.0-alpine3.13 build: context: ./app/ dockerfile: ../docker/app/Dockerfile environment: RAILS_DATABASE_HOST: db RAILS_DATABASE_USERNAME: root RAILS_DATABASE_PASSWORD: password ports: - 3000:3000 depends_on: - db web: image: boccifarm/nginx:1.18.0-alpine build: context: ./docker/web/ ports: - 80:80 depends_on: - app volumes: db:まずはdocker-composeが正常に起動することを確認
% DOCKER_BUILDKIT=1 COMPOSE_DOCKER_CLI_BUILD=1 docker-compose build % docker-compose up -d
ブラウザから確認します。
http://localhost/
問題なければdocker-composeを落としておきます。
% docker-compose stopkomposeを使ってk8sマニフェストファイルを作成
% mkdir -p k8s/overlays/local % kompose convert --volumes hostPath -o k8s/overlays/local
k8sマニフェストファイルの編集
作成されるのはあくまで雛形なので自分の環境に合うように微調整します。
hostPathのpathにdocker volumeを指定する
こうすることでdocker-composeで使用していたdocker volumeを共用できます。
k8s/overlays/local/db-deployment.yaml41 volumes: 42 - hostPath: 43 path: docker-rails_db # <= docker volumeに変更ローカルのイメージを使用するようにimagePullPolicy: Neverを追加
imagePullPolicy: Neverを設定するとローカルにあるイメージを使うように強制できます。
k8s/overlays/local/app-deployment.yaml34 image: boccifarm/rails:6.1.3-ruby3.0.0-alpine3.13 35 imagePullPolicy: Never # <= 追加k8s/overlays/local/db-deployment.yaml31 image: boccifarm/mysql:8.0.23 32 imagePullPolicy: Never # <= 追加k8s/overlays/local/web-deployment.yaml27 - image: boccifarm/nginx:1.18.0-alpine 28 imagePullPolicy: Never # <= 追加serviceのTypeをNodePortにする
ローカル環境なのでserviceのTypeをNodePortにします。
今回はweb(nginx)だけ外からアクセスできればいいので、web-service.yamlのみ編集します。k8s/overlays/local/web-service.yaml11 spec: 12 ports: 13 - name: "80" 14 port: 80 15 targetPort: 80 16 selector: 17 io.kompose.service: web 18 type: NodePort # <= 追加k8sの起動
% kubectl apply -f k8s/overlays/local % kubectl get po,deploy,svc NAME READY STATUS RESTARTS AGE pod/app-b75844fb8-24fqx 1/1 Running 0 17s pod/db-9cb76c59d-tvmtq 1/1 Running 0 17s pod/web-785bb88999-nkxkd 1/1 Running 0 17s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/app 1/1 1 1 17s deployment.apps/db 1/1 1 1 17s deployment.apps/web 1/1 1 1 17s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/app ClusterIP 10.102.65.9 <none> 3000/TCP 17s service/db ClusterIP 10.98.6.248 <none> 3306/TCP,33060/TCP 17s service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 16d service/web NodePort 10.110.198.177 <none> 80:31427/TCP 17sブラウザから確認します。ポートはNodePort(今回は31427)を指定します。
http://localhost:31427/
以上
- 投稿日:2021-03-05T16:31:39+09:00
LaravelのMySQLデータベースをXAMPPからDockerに切り替え
自分はこのやり方でできたという記録用です。私はXAMPPを使っていましたが、Dockerに切り替えたいと思います。
既にアプリの中身は完成している状態から始めます。プロジェクトのターミナルでDocker imageをダウンロード
docker pull mysqlmysqlサーバーを立てる
docker run --name mysql-server -e MYSQL_ROOT_PASSWORD="admin" -d -p 53306:3306 mysqlmysqlへログイン
mysql -uroot -padmin -h 127.0.0.1 -P 53306XAMPPで作成していたデータベースをDockerのmysqlでも作成します。
新しいデータベースをXAMPPのものと同じように作り変えます。php artisan migrate:freshエラー
SQLSTATE[HY000] [2054] The server requested authentication method unknown to the client (SQL: SHOW FULL TABLES WHERE table_type = 'BASE TABLE')
認証方式を変えます。
SELECT user, host, plugin FROM mysql.user; //私の結果 +------------------+-----------+-----------------------+ | user | host | plugin | +------------------+-----------+-----------------------+ | root | % | caching_sha2_password | | mysql.infoschema | localhost | caching_sha2_password | | mysql.session | localhost | caching_sha2_password | | mysql.sys | localhost | caching_sha2_password | | root | localhost | caching_sha2_password | +------------------+-----------+-----------------------+私の場合rootの二つを変えました。
alter user 'root'@'%' identified with mysql_native_password by 'pass'; alter user 'root'@'localhost' identified with mysql_native_password by 'pass';envファイルを書き換えます。
DB_CONNECTION=mysql DB_HOST=localhost //変更 DB_PORT=53306 //変更 DB_DATABASE=database_name //自分が新しく作ったデータベース名 DB_USERNAME=root DB_PASSWORD=pass //先程のパスワードここまでできたらマイグレーションします。
php artisan migrate:freshphp artisan serveと打つとデータベースにデータが入っていない状態で立ち上がると思います。シーダーファイルの中身を入れます。
php artisan db:seedこれでデータベースの移行が完了しました。
参考
https://tyablog.net/2017/06/10/docker-setup-mysql/
https://symfoware.blog.fc2.com/blog-entry-2160.html
- 投稿日:2021-03-05T11:59:17+09:00
RailsのDockerイメージの作り方
0. はじめに
以下のようなディレクトリ構成にします。
. ├── app/ # Railsアプリ └── docker/ # Dockerfile置き場 └── app/ └── Dockerfile1. ローカル環境にRailsをインストール
% rails new app
2. Dockerfileの作成
docker/app/Dockerfile# syntax=docker/dockerfile:1.2 # base FROM ruby:3.0.0-alpine3.13 AS base WORKDIR /app RUN \ --mount=type=cache,target=/var/cache/apk \ apk add -U \ build-base \ git \ nodejs \ sqlite-dev \ tzdata \ yarn \ ; # bundle FROM base AS bundle COPY Gemfile Gemfile.lock /app/ RUN \ --mount=type=cache,target=/app/vendor/cache \ bundle install && \ bundle cache # yarn FROM base AS node_modules COPY package.json yarn.lock /app/ RUN \ --mount=type=cache,target=/usr/local/share/.cache/yarn/v4 \ yarn install # main FROM base ARG RAILS_MASTER_KEY ENV RAILS_MASTER_KEY $RAILS_MASTER_KEY COPY --from=bundle /usr/local/bundle/ /usr/local/bundle/ COPY --from=node_modules /app/node_modules/ /app/node_modules/ COPY . /app/ EXPOSE 3000 CMD ["bundle", "exec", "rails", "s", "-b", "0.0.0.0"]3. .dockerignoreの用意
不要なファイルをイメージに含めないために.dockerignoreを作成します
app/.dockerignore/.bundle/ /.dockerignore /.git/ /.git* /.ruby-version /README.md /config/master.key /log/ /node_modules/ /storage/ /tmp/ /vendor/bundle/4. Dockerイメージのビルド
% DOCKER_BUILDKIT=1 docker image build --build-arg RAILS_MASTER_KEY=<RAILS_MASTER_KEY> -t boccifarm/rails:6.1.3-ruby3.0.0-alpine3.13 -f docker/app/Dockerfile app5. Dockerイメージのプッシュ
% docker login % docker image push boccifarm/rails:6.1.3-ruby3.0.0-alpine3.13
- 投稿日:2021-03-05T09:05:06+09:00
【Docker】Ruby2.6.5とRails6.0.0とmysql DockerComposeで環境構築
はじめに
Ruby2.6.5とRails6.0.0とmysqlでDockerComposeで環境構築をしたので記録として記事を書きます。
もし誰かのお役に立てたら幸いです。Docker環境でアプリケーション開発する手順
1、RailsのDockerfileを作成してDockerをbuild
2、DockerCompose.ymlを作成しコンテナを作る
3、Rails のセットアップ
4、データベースを作成する開発環境
Docker version 20.10.0
docker-compose version 1.27.41、RailsのDockerfile作成
新しいデレクトリを作成します。
今回はデレクトリ名をexamとしてます。ターミナルmkdir [新規デレクトリ名] cd [新規デレクトリ名]Dockerfile
新規で作ったデレクトリに「Dockerfile」をいう名前でDockerファイルを作成します。
VSコードをお使いの方はcode Dockerfile
でターミナルから直接ファイルの作成&移動をしてくれます。
もちろんディレクトリを呼び込んでファイルを作成しても大丈夫です。exam/DockerfileFROM ruby:2.6.5 RUN apt-get update && apt-get install -y \ build-essential \ libpq-dev \ nodejs\ yarn \ vim WORKDIR /新規デレクトリ名 COPY Gemfile Gemfile.lock /新規デレクトリ名/ RUN bundle installGemファイルを作成する
ターミナルtouch Gemfile Gemfile.lockGemfileにファイルを持ってくるソースとrailsのバージョンを記述します。
Gemfilesource 'https://rubygems.org' gem 'rails', '~>6'Dockerを建てます。
ターミナルdocker build . . . . Installing rails 6.1.2.1 Bundle complete! 1 Gemfile dependency, 42 gems now installed. Use `bundle info [gemname]` to see where a bundled gem is installed. Removing intermediate container 06448279a57c ---> c21a3ec7e3a4 Successfully built c21a3ec7e3a4 #イメージが出来てるか調べる事も出来ます。 docker images #もし使っていないイメージがあれば下記のコマンドで削除できます。 docker rmi [IMAGE ID]2、DockerCompose.ymlを作成しコンテナを作る
dockerc-compose.ymlファイルを作成し記述する
ターミナルcode docker-compose.ymlこれで新しい
docker-compose.yml
が作成されます。docker-compose.ymlversion: '3' services: web: build: . ports: - 3000:3000 volumes: - '.:/[作成したディレクトリ名]' tty: true stdin_open: true
dockerc-ompose.yml
の確認をして実行します#確認します cat docker-compose.yml #実行します docker-compose up -d #コンテナが動いてる事を確認します。 docker ps docker-compose ps #コンテナの中に入ります。 docker-compose exec web bash3、Rails のセットアップ
Railsの環境でコンテナができのでその中で
rails new
をしてセットアップして行きます。#新しいrailsを作ります rails new . --force --database=mysql --skip-bundle #一度コンテナから抜けます exit #今のコンテナとイメージを削除します docker-compose down #Downになってるか確認します docker ps #新しいイメージでコンテナを建てます docker-compose up --build -d #確認します docker-compose ps #コンテナに入ります docker-compose exec web bash #Railsを起動します rails s -b 0.0.0.0 #現段階ではエラーが出ます現段階ではデータベースの記述を Dockerfileに記述していないので、mysql2のエラーが出ると思います。
下記の対応を試して下さい。【Docker】エラー Could not find gem 'mysql2 (~> 0.5)' in any of the gem sources listed in your Gemfile
https://qiita.com/AKI3/items/8009b5218be0ad67b6b7エラーが解決したら
rails s -b 0.0.0.0
でサーバーが立ち上がります。
実際にlocalhost:3000
でアクセスします。
しかしこのままではデータベースが無いのでエラー画面が表示されます。
4、データベースを作成する。
ローカルであれば
rails db:create
をするとデータベースを作れるのですが、コンテナ内では現状の設定では作れません。
Dockerではサービス(環境)ごとにコンテナを作る事が推奨されております。
今回であればRubyとmysqlのコンテナを別々に作り、それぞれのコンテナどうしを接続する必要があります。
その為、detabase.ymlの設定ファイルを編集して正しい指定をし、docker-compose.ymlの設定ファイルの編集します。先ずdetabase.ymlを編集します。
config/detabase.ymldefault: &default adapter: mysql2 encoding: utf8 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> host: db development: <<: *default database: 新規デレクトリ名_development username: root password: 省略次にdocker-compose.ymlを編集します。
docker-compose.ymlversion: '3' volumes: db-data: services: web: build: . ports: - 3000:3000 volumes: - '.:/新規デレクトリ名' environment: - 'MYSQL_ROOT_PASSWORD=1' tty: true stdin_open: true depends_on: - db links: - db db: image: mysql:8 volumes: - 'db-data:/var/lib/mysql' # このenvironmentはテスト環境でのみ使用可能 environment: MYSQL_ALLOW_EMPTY_PASSWORD: 1 # command: bundle exec rails s -p 3000 -b '0.0.0.0' #こちらはお好みでdocker-compose.ymlを編集したので新しくコンテナを作ります。
今回はweb(Raisl)とdb(mysql)2つのコンテナを作る事になります。#再びコンテナを建てます docker-compose up -d #upになってるか確認します docker-compose ps #コンテナに入ります docker-compose exec web bash #データベースを作成します rails db:create #現段階ではエラーが出ますRails側のコンテナ内で作業を進めていきます。
先程作ったRails側のコンテナとmysql側のコンテナがしっかり繋がっていればrails db:create
のコマンドは通りますが、現段階では下記のエラーが発生します。Mysql2::Error::ConnectionError: Plugin caching_sha2_password could not be loaded: /usr/lib/x86_64-linux-gnu/mariadb19/plugin/caching_sha2_password.so: cannot open shared object file: No such file or directoryこれはwebコンテナが mysql 8.0 の
caching_sha2_password
が認証方式に対応していないためだそうです。詳しくは、こちらの記事で解決できます。
https://blog.toshimaru.net/rails-on-docker-compose/コマンドだけこちらに記載します。
ターミナル#データベース側のコンテナに入る docker-compose exec db bash #mysqlを操作する mysql -u root #ユーザー一覧とその認証方式が閲覧 select User,Host,plugin from mysql.user; #root@% のユーザー設定を変更 ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY ''; #再度ユーザー一覧とその認証方式が閲覧 select User,Host,plugin from mysql.user;エラーが解決できたら最後サーバーを立ち上げます。
ターミナルrails s -b 0.0.0.0 => Booting Puma => Rails 6.1.2.1 application starting in development => Run `bin/rails server --help` for more startup options Puma starting in single mode... * Puma version: 5.2.1 (ruby 2.6.5-p114) ("Fettisdagsbulle") * Min threads: 5 * Max threads: 5 * Environment: development * PID: 29 * Listening on http://0.0.0.0:3000 Use Ctrl-C to stop . . . 省略出来ました!
localhost3000
にアクセスすると-Yay! You’re on Rails!-の画面が表示されます。
最後に
手探りの対処療法でサーバー起動まで達成しましので、これからも継続学習が必要です。
なんとか環境構築まで至りましたが、Dockerについて完全に理解できておりません、万が一情報が間違っている場合ご指摘していただけると幸いです。エンジニア初学者ですが、同じ様に悩んでる方々の助けになればと思い記事を投稿しております。
万が一情報が間違っている場合ご指摘していただけると幸いです。参考
今回Udemyの教材とやっすんのエンジニア大学を主に参考にさせていただきました。
https://www.udemy.com/course/aidocker/
https://github.com/yassun-youtube/docker-compose-sample/blob/master/docker-compose.yml
- 投稿日:2021-03-05T00:49:56+09:00
PHPUnitでHTMLコードガバレッジを出すまで(Docker使用)
はじめに
以下記事の【phpunitを少し使ってみる】までは行っている前提で話します。
最終的表示までのものgithubにあげているのでもしよかったら見てください。
どこに何を書けばいいかもここのファイル等見てもらった方が早いかもです。
最終的な見た目は以下のような感じです。
上記の【phpunitさわるまで】以降にすること箇条書き
※HTMLでコードガバレッジを表示するのに必要な設定
- 【step1】 tokenizer(拡張モジュール)追加
- 【step2】 Xdebug(拡張モジュール)追加
- 【step3】 php.iniの設定、反映(Xdebug(拡張モジュール)有効化)
- 【step4】 phpunit.xml(コードガバレッジ出力のための設定ファイル的なもの)の作成
- 【step5】 メソッドの修正
- 【step6】 最後に出力コマンド
【step1】 tokenizer(拡張モジュール)追加
Dockerfileに以下追記
※ですがもしかしたらこれいらないかもしれないです、、すでに入ってる的なログ出てた気がするので念のため書いておきます、、DockerfileRUN docker-php-ext-install tokenizer【step2】 Xdebug(拡張モジュール)追加
Dockerfileに以下追記。すでに記述してある処理はそのままで。
ちなみに『apt-get』使用でインストール出来なかったのでこのインストールの方法で行っています。
peclのインストールがwget
インストールしたpeclでxdebugをインストールするという感じです。インストール方法は以下の記述参考
https://pear.php.net/manual/en/installation.getting.phppeclでインストールできるもの以下
https://pecl.php.net/package-stats.phpDockerfileRUN apt-get update \ && apt-get install -y \ wget # コードジェネレーターで必要 RUN pecl install xdebug【step3】 php.iniの設定、反映(Xdebug(拡張モジュール)有効化)
xdebug使えるようにするためphp.iniを自分で作成してDockerの環境に反映するをしました。
ちなみに
extension=xdebug.so
の記述書け!は以下リンク先に書かれていたもので
http://xdebug.org/docs/install
xdebug.mode=coverage
の記述書け!は失敗ログで言われたものです。Warning: XDEBUG_MODE=coverage or xdebug.mode=coverage has to be setDockerfileに以下追記
DockerfileCOPY html/php.ini /usr/local/etc/php/conf.dphp.iniを以下場所に作成
html/php.iniextension=xdebug.so xdebug.mode=coverage【step4】 phpunit.xml(コードガバレッジ出力のための設定ファイル的なもの)の作成
『docker-compose.yml』ある場所で
$ docker-compose up --build -d
を叩きます。以下コマンド今使用しているコンテナIDの確認を行う
$ docker ps
コンテナ内に以下コマンドで入る、 ※『1999d283b4f9』は上記で出力したコンテナIDを使用してください
$ docker exec -i -t 1999d283b4f9 bash
phpunit.xmlの作成コマンドを打つ、そして聞かれた内容に答えていく
$ vendor/bin/phpunit --generate-configuration
【step5】 メソッドの修正
テストメソッド上の何のテストをするかを記述(
@covers
の部分)
これないとThis test does not have a @covers annotation but is expected to have one
と言われます。/** * @covers sample\Sample::a **/ public function testA()全体
https://github.com/sachiko-kame/samplePHPTest/blob/main/html/TEST/SampleTest.php【step6】 最後に出力コマンド
これで『TestResult』フォルダ内に無事index.htm等々作成出来て表示に問題がなければOKです!
うまくいかない場合『phpunit.xml』が同じでない可能性が高いと思うので以下と見合わせていただければと思います。
https://github.com/sachiko-kame/samplePHPTest/blob/main/html/phpunit.xml
$ vendor/bin/phpunit --coverage-html TestResult
参考
https://tech-blog.rakus.co.jp/entry/20200908/docker
https://docs.docker.jp/engine/reference/builder.html#copy
その他所々にリンク貼ってます!
- 投稿日:2021-03-05T00:49:56+09:00
PHPUnitでHTMLコードカバレッジを出すまで(Docker使用)
はじめに
以下記事の【phpunitを少し使ってみる】までは行っている前提で話します。
最終的表示までのものgithubにあげているのでもしよかったら見てください。
どこに何を書けばいいかもここのファイル等見てもらった方が早いかもです。
最終的な見た目は以下のような感じです。
上記の【phpunitさわるまで】以降にすること箇条書き
※HTMLでコードカバレッジを表示するのに必要な設定
- 【step1】 tokenizer(拡張モジュール)追加
- 【step2】 Xdebug(拡張モジュール)追加
- 【step3】 php.iniの設定、反映(Xdebug(拡張モジュール)有効化)
- 【step4】 phpunit.xml(コードカバレッジ出力のための設定ファイル的なもの)の作成
- 【step5】 メソッドの修正
- 【step6】 最後に出力コマンド
【step1】 tokenizer(拡張モジュール)追加
Dockerfileに以下追記
※ですがもしかしたらこれいらないかもしれないです、、すでに入ってる的なログ出てた気がするので念のため書いておきます、、DockerfileRUN docker-php-ext-install tokenizer【step2】 Xdebug(拡張モジュール)追加
Dockerfileに以下追記。すでに記述してある処理はそのままで。
ちなみに『apt-get』使用でインストール出来なかったのでこのインストールの方法で行っています。
peclのインストールがwget
インストールしたpeclでxdebugをインストールするという感じです。インストール方法は以下の記述参考
https://pear.php.net/manual/en/installation.getting.phppeclでインストールできるもの以下
https://pecl.php.net/package-stats.phpDockerfileRUN apt-get update \ && apt-get install -y \ wget # コードジェネレーターで必要 RUN pecl install xdebug【step3】 php.iniの設定、反映(Xdebug(拡張モジュール)有効化)
xdebug使えるようにするためphp.iniを自分で作成してDockerの環境に反映するをしました。
ちなみに
extension=xdebug.so
の記述書け!は以下リンク先に書かれていたもので
http://xdebug.org/docs/install
xdebug.mode=coverage
の記述書け!は失敗ログで言われたものです。Warning: XDEBUG_MODE=coverage or xdebug.mode=coverage has to be setDockerfileに以下追記
DockerfileCOPY html/php.ini /usr/local/etc/php/conf.dphp.iniを以下場所に作成
html/php.iniextension=xdebug.so xdebug.mode=coverage【step4】 phpunit.xml(コードカバレッジ出力のための設定ファイル的なもの)の作成
『docker-compose.yml』ある場所で
$ docker-compose up --build -d
を叩きます。以下コマンド今使用しているコンテナIDの確認を行う
$ docker ps
コンテナ内に以下コマンドで入る、 ※『1999d283b4f9』は上記で出力したコンテナIDを使用してください
$ docker exec -i -t 1999d283b4f9 bash
phpunit.xmlの作成コマンドを打つ、そして聞かれた内容に答えていく
$ vendor/bin/phpunit --generate-configuration
【step5】 メソッドの修正
テストメソッド上の何のテストをするかを記述(
@covers
の部分)
これないとThis test does not have a @covers annotation but is expected to have one
と言われます。/** * @covers sample\Sample::a **/ public function testA()全体
https://github.com/sachiko-kame/samplePHPTest/blob/main/html/TEST/SampleTest.php【step6】 最後に出力コマンド
これで『TestResult』フォルダ内に無事index.htm等々作成出来て表示に問題がなければOKです!
うまくいかない場合『phpunit.xml』が同じでない可能性が高いと思うので以下と見合わせていただければと思います。
https://github.com/sachiko-kame/samplePHPTest/blob/main/html/phpunit.xml
$ vendor/bin/phpunit --coverage-html TestResult
参考
https://tech-blog.rakus.co.jp/entry/20200908/docker
https://docs.docker.jp/engine/reference/builder.html#copy
その他所々にリンク貼ってます!