モノレポでのDocker運用注意点!
はじめに
こんにちは畑田です。
最近のプロジェクトの開発において、Djangoのstatic file群のみをHTTPサーバ(今回はnginx)から配信する方針を選択しました。
ECRにDjangoとnginxのimageを置いておいて、container生成を行っています。
このとき、nginxのimageの中にDjangoのstatic file群を配置しなければならないのですが、Djangoのstatic file群はnginxのDockerfile以下に無いため、Dockerfile内での記述方法がわからず困ってしまいました。
基本を勉強し直すことで解決できたので記録に残します。
環境
- Docker Version: 20.10.2
- Docker API version: 1.41
問題
まず、今回のプロジェクトのディレクトリ構造は以下の様です。(docker-compose.yml
やsql/
以下は当記事とは無関係です。)
.
├── .gitignore
├── README.md
├── docker-compose.yml
├── nginx
│ ├── Dockerfile <<<<<<<< こいつから
│ ├── conf
│ │ └── default.conf
│ ├── nginx.conf
│ └── uwsgi_params
├── server
│ ├── .dockerignore
│ ├── Dockerfile
│ ├── Dockerfile.prod
│ ├── requirements.txt
│ └── src
│ ├── .env
│ ├── .env.dev
│ ├── event_master
│ ├── manage.py
│ ├── pjevent
│ ├── shop_master
│ ├── static <<<<<<<< こいつを参照したい
│ ├── user_master
│ └── uwsgi.ini
└── sql
├── Dockerfile
├── init
│ └── init.sql
└── my.cnf
今回、nginx/Dockerfile
からserver/src/static/
を指定し、COPY
によってstatic file群をnginxサーバーに置くことがゴールです。
しかし、Dockerfileにおいて、local側のpathはDockerfileのあるdirectory以下の階層しか指定できないのです。つまり、local側のpathは./
以下しかDockerfileには記述できません。
今回、nginx/Dockerfile
からserver/src/static/
への相対pathは../sever/static/
であるため、nginx/Dockerfile
で管理できないのではないかと悩みました。
基本を復習
Dockerfileからimageをビルドするコマンドでよく使うのは以下です。
$ docker image build -t IMAGE_NAME:IMAGE_TAG .
そもそも-t
オプションは--tag
オプションの省略形で、imageにnameとtag(tagはオプショナル)をつけるためのものです。
最後につけてある.
はこのコマンドの引数であり、Dockerfileにとってのcurrent directoryを指定します。
これについて、僕は参照したいDockerfileの位置するdirectoryを指定するものだと勘違いしていました。(これを勉強し直すことで今回のお悩みは解決されました。)
さて、よく使うオプションは--tag
の他に--file
があります。
--file
オプションでは、Dockerfileとして使用するfileへのpathを指定することができます。デフォルトではcurrent directoryのDockerfile
を探して読み込みますが、実際はここで指定してやれば、なんという名前のものでも良いです。
Dockerfile.prod
という名前で本番環境用のものを用意したり、Dockerfile.base
という名前でbase imageのためのものを用意したりできます。
実際に打ったコマンド
答えです。
プロジェクトのrootに移動して、以下のコマンドを打ちます。
$ docker image build --tag pj-event-nginx --file nginx/Dockerfile .
nginx/Dockerfile
の内容は以下です。
FROM nginx:1.19.1
COPY ./nginx/conf/default.conf /etc/nginx/conf.d/default.conf
COPY ./nginx/nginx.conf /etc/nginx/nginx.conf
COPY ./nginx/uwsgi_params /etc/nginx/uwsgi_params
COPY ./server/src/static /static
CMD /usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.conf
EXPOSE 80
このコマンドの妙は、nginx/Dockerfile
にとってのcurrent directoryにroot(.
)を指定しているところです。
Dockerfileが位置するdirectoryとDockerfileにとってのcurrent directoryが違うのです。
こうすることによって、Dockerfileにとっての./
が、rootを表すため、../
を使わずにserver/src/static/
にpathを通すことができる様になります。
もちろん以下の様なコマンドも同義です。
$ cd nginx/
$ docker image build --tag pj-event-nginx --file ./Dockerfile ..
ここで、./Dockerfile
とだけ--file
オプションに指定しているのは、書かないとデフォルトでcurrent directory(引数である../
)のDockerfile
という名前のファイルを探してしまうためです。今回はこのコマンドを打っているdirectoryにDockerfileがあるのでこの様に指定しました。
結論
実現したいこと自体はコマンドを正確に使えば十分表現できることでした。
docker image build
コマンドについて、以下の様に整理しておきます。
引数はDockerfileにとってのcurrent directoryを指定します。
--file
オプションは参照したいDockerfileへのpathを指定するもので、デフォルトでは引数で指定したdirectory内のDockerfile
という名前のファイルを探して参照します。
Dockerfileの位置するdirectoryの親階層からしかアクセスできないfileを参照したい場合は、Dockerfileは親階層をcurrent directory(./
)として記述し、ビルドするときの引数にも親階層を指定してあげれば実現できます。
その際注意すべきは、Dockerfileが位置するdirectoryとDockerfileにとってのcurrent directoryが違うので--file
オプションが必要であるということです。
以上です。
参考
Discussion