🐬

モノレポでのDocker運用注意点!

2024/06/29に公開

はじめに

こんにちは畑田です。
最近のプロジェクトの開発において、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.ymlsql/以下は当記事とは無関係です。)

.
├── .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オプションが必要であるということです。
以上です。

参考

https://docs.docker.com/engine/reference/builder/

R&Dテックブログ

Discussion