前提
誰も気になってないのかもしれないけど、ピンポイントの情報が見つけられなかったので
動作確認環境
サービス名
本記事では、以下に示す部分で指定した名称をサービス名と称します
version: '3.8'
services:
srv1: # <- ここ!
image: node:14
単一Composeファイルの場合
単一Composeファイルでは、同じサービス名を定義すると
後に定義された側が優先され、同時に起動することはありません
version: '3.8'
services:
srv1:
image: node:14
container_name: node14
srv1:
image: node:12
container_name: node12
$ docker compose up
[+] Running 2/2
⠿ Network compose_demo_default Created 0.0s
⠿ Container node12 Started 2.3s
Attaching to node12
node12 exited with code 0
複数Composeファイルで、同一のdocker networkに所属させる
同一フォルダ階層にある複数のComposeファイルにて
同名のサービスを立ち上げようとした場合も、
上記と同様の結果となります(後からcompose upしたものにRecreateされる)
そのため、Composeファイルを別フォルダに置くか、
実行時に-p
オプションを用いて別プロジェクトとして認識させる必要があります。
version: '3.8'
networks:
default:
name: local_link
services:
srv1:
image: nginx:latest
container_name: app1
version: '3.8'
networks:
default:
name: local_link
services:
srv1:
image: nginx:latest
container_name: app2
$ docker compose -p app1 -f docker-compose.app1.yml up -d
[+] Running 2/2
⠿ Network local_link Created 0.0s
⠿ Container app1 Started 0.8s
$ docker compose -p app2 -f docker-compose.app2.yml up -d
[+] Running 1/1
⠿ Container app2 Started 0.9s
確認
docker network inspect
で確認
$ docker network inspect local_link
(略)
"Containers": {
"09d61a2de...": {
"Name": "app2",
...
},
"0cdf3f601...": {
"Name": "app1",
...
}
},
(略)
同一のネットワークに属している。
更に、各コンテナの情報を確認
$ docker inspect app1
(略)
"Networks": {
"local_link": {
"Aliases": [
"app1",
"srv1",
"0cdf3f601f16"
],
(略)
$ docker inspect app2
(略)
"Networks": {
"local_link": {
"Aliases": [
"app2",
"srv1",
"09d61a2dea34"
],
(略)
ネットワークエイリアスとして
- コンテナ名
- サービス名
- コンテナID
が登録されているのがわかる。
別のアプリに同じサービス名が登録されたこの状態で
srv1にアクセスしたらどうなるのか、が今回の主題です。
auto scaleの話
本題に入る前に、
同じサービス名が複数のコンテナに紐付けらることが望ましい状況として
スケールアウトさせたい場合が考えられます。
確認してみると
version: '3.8'
services:
srv1:
image: nginx:latest
# container_name: app1 # コンテナ名はユニークなのでスケールさせる場合は指定できない
networks:
default:
name: local_link
$ docker compose -p app1 -f docker-compose.app1.yml up -d --scale srv1=2
[+] Running 3/3
⠿ Network local_link Created 0.0s
⠿ Container app1_srv1_2 Started 0.8s
⠿ Container app1_srv1_1 Started 0.7s
$ docker network inspect local_link
(略)
"Containers": {
"5dd3a0844....": {
"Name": "app1_srv1_2",
...
},
"d926584e....": {
"Name": "app1_srv1_1",
...
}
},
$ docker inspect app1_srv1_1
(略)
"Networks": {
"local_link": {
"Aliases": [
"app1_srv1_1",
"srv1",
"d926584e7947"
],
(略)
$ docker inspect app1_srv1_2
(略)
"Networks": {
"local_link": {
"Aliases": [
"app1_srv1_2",
"srv1",
"5dd3a08445a7"
],
(略)
(当然かもしれませんが)想定通り、同じサービス名でエイリアスが登録されています
本題
下記の設定で立ち上げたnginxから、それぞれにアクセスしてみます
version: '3.8'
services:
proxy:
image: nginx:latest
container_name: proxy
volumes:
- ./default.conf:/etc/nginx/conf.d/default.conf
ports:
- 8080:80
networks:
default:
name: local_link
server {
listen 80;
listen [::]:80;
server_name localhost;
location /app1/ {
proxy_pass http://app1:8080/;
}
location /app2/ {
proxy_pass http://app2:8080/;
}
location /srv1/ {
proxy_pass http://srv1:8080/;
}
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
app1, app2
今回はgolangで作りました。
app1とapp2の差分がある部分は、同行にコメントで記しました。
package main
import (
"fmt"
"net/http"
)
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, from app1") // app2では Hello, from app2
}
func main(){
http.HandleFunc("/", hello)
http.ListenAndServe(":8080", nil)
}
FROM golang:1.16 AS build-env
WORKDIR /app
COPY . .
RUN go get && go build -o serve.out
FROM gcr.io/distroless/base
WORKDIR /app
COPY --from=build-env /app/serve.out .
CMD ["./serve.out"]
EXPOSE 8080
version: '3.8'
services:
srv1:
build:
context: .
image: app1:latest # app2:latest
container_name: app1 # app2
networks:
default:
name: local_link
結果
auto scale の話をした時点でなんとなく予想できていたが、
同じサービス名のコンテナに交互にアクセスしている模様。
スケールさせたときのロードバランシングの仕様を調べれば、どうなっているか分かると思います。
結論
別のアプリに同じサービス名を与え、同じネットワーク内に配備していると
予期せぬアクセスが発生する可能性がある。
さいごに
networksの書き方で下記のようにnameを指定すると、
externalを指定しなくてもCompose外部に定義されているnetwork探してくれる上、
upと同時に無ければ作成され、downと同時に利用されてなければ削除される
という発見があった
version: '3.8'
networks:
default:
name: local_link
tmpname:
name: my-net1
services:
srv1:
image: nginx:latest
networks:
- default
- tmpname
networkが作成されたプロジェクトに紐付けされるので、
消す順番によってはnetworkだけが消えずに残ることもあるので注意
(再度downすれば消えるので大きな問題ではないが)