それぞれ違うコンテナにアクセスできるようにするまでに時間がかかったのでメモ。
例えばフロントエンドとバックエンドがあって、それぞれ別々に git で管理するのが普通だと思う。
そしてそれぞれに docker-compose.yaml があるのも多分普通だと思う。
Docker 初心者(自分)が普通に書いていくと別コンテナから別コンテナにアクセスできないことがわかってきた。
別コンテナにアクセスするには同じネットワーク内でコンテナを起動しないとアクセスできない。
(他に方法があるかもしれないけど、この方法が1番しっくりきた)
また、 localhost:8080 でポート番号を変更してそれぞれ管理するのは厳しいと思ったので、
ドメインで管理できるように nginx-proxy を使った。
同じネットワーク内で指定したドメインで別コンテナに cURL でアクセスすると
「curl: (7) Failed to connect to xxxx.xxx port 80: Connection refused」
というエラーが起きたのでこれも解決するのに時間がかかった。
環境
- MacBook Pro (macOS: Big Sur)
ファイル構成
/backend
├ /app
│ └ /public
│ └ index.html
├ docker-compose.yaml
├ Dockerfile
└ /nginx
└ default.conf
/frontend
├ /app
│ ├ /bin
│ │ └ composer
│ ├ composer.json
│ └ /public
│ └ index.html
├ docker-compose.yaml
├ Dockerfile
└ /nginx
└ default.conf
/nginx-proxy
└ docker-compose.yaml
サンプルコード (nginx-proxy)
- localhost:8080 ではなく、ドメインでアクセスできるようにする。
nginx-proxy/docker-compose.yaml
- ポート番号を 8080 から 80 にする。
- ポート番号をつけなくてもよくなる。
- jwilder/nginx-proxy を使うことによってドメインで管理できるようになる。
- 「docker-sample-network」というネットワークで別々のコンテナを繋ぐ
version: "3"
services:
app:
container_name: nginx-proxy
image: jwilder/nginx-proxy
ports:
- 80:80
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
networks:
- docker-sample-network
networks:
docker-sample-network:
name: docker_sample_network
サンプルコード (backend)
- 適当なバックエンドを用意する。
- 1行文字列を返すだけ
backend/docker-compose.yaml
- ドメイン名を「api.docker.sample」にする。
- http://api.docker.sample でアクセスできる
- コンテナ名を「docker_sample_api」に固定する。
- http://docker_sample_api でアクセスできる(cURL )
- ネットワーク名「docker-sample-network」を使用する。
version: "3"
services:
app:
build:
context: .
container_name: docker_sample_api
volumes:
- ./app:/var/www/html
networks:
- docker-sample-network
environment:
- VIRTUAL_HOST=api.docker.sample
networks:
docker-sample-network:
name: docker_sample_network
backend/Dockerfile
FROM nginx:1
WORKDIR /var/www/html
COPY ./app /var/www/html
COPY ./nginx/default.conf /etc/nginx/conf.d/default.conf
backend/app/public/index.html
1行返すだけの適当な html ファイル
hello world, docker-sample/nginx-proxy-frontend-backend/backend
backend/nginx/default.conf
server {
listen 80;
listen [::]:80;
server_name localhost;
root /var/www/html/public;
index index.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
location ~ /\.ht {
deny all;
}
}
サンプルコード (frontend)
- 適当に用意したフロントエンドでバックエンドに cURL でアクセスする。
- cURL でアクセスする時は「コンテナ名 (container_name)」でアクセスする。
- Ajax でアクセスする時は「ドメイン名」でアクセスうする。
- コンテナを起動させてそのコンテナにログインして、
「$ curl [container_name]」すればいいだけなんだけど、
今回はフロントエンドもドメイン指定してるのでそれっぽく作ってみた。
frontend/docker-compose.yaml
- ドメイン名を「docker.sample」にする。
- http://docker.sample でアクセスできる
- ネットワーク名「docker-sample-network」を使用する。
- php コンテナにも networks: docker-sample-network を指定しないと PHP が動かない。
- 適当に PHP-fpm を使う。
- app と php それぞれに volumes: に「- ./app:/var/www/html」 してるのは、
app だけに記述すると PHP が動かず、
php だけに記述すると PHP 以外のファイルを更新するとうまく同期されなかったため。
- app と php それぞれに volumes: に「- ./app:/var/www/html」 してるのは、
version: "3"
services:
app:
build:
context: .
volumes:
- ./app:/var/www/html
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
depends_on:
- php
networks:
- docker-sample-network
environment:
- VIRTUAL_HOST=docker.sample
php:
# https://hub.docker.com/_/php
image: php:fpm
volumes:
- ./app:/var/www/html
networks:
- docker-sample-network
networks:
docker-sample-network:
name: docker_sample_network
frontend/Dockerfile
FROM nginx:1
WORKDIR /var/www/html
COPY ./app /var/www/html
COPY ./nginx/default.conf /etc/nginx/conf.d/default.conf
frontend/app/bin/composer
frontend/app/composer.json
{
"require": {
"guzzlehttp/guzzle": "^7.2"
}
}
frontend/app/public/index.php
- cURL でアクセスする時は「コンテナ名 (container_name)」を指定する。
- Ajax でアクセスする時は「ドメイン名」を指定する。
- 今回は cURL で試すので Guzzle を使う。
- http://docker_sample_api
- ドメイン名を指定すると「curl: (7) Failed to connect to xxxx.xxx port 80: Connection refused」というエラーが起きる。
- Guzzle のサンプルコードをほとんどそのまま使用。
<!DOCTYPE html>
<html lang="ja" dir="ltr">
<head>
<meta charset="utf-8">
<title>docker-sample/nginx-proxy-frontend-backend/frontend</title>
</head>
<body>
<h1>hello world</h1>
<p>docker-sample/nginx-proxy-frontend-backend/frontend</p>
<hr>
<h2>cURL</h2>
<a href="http://api.docker.sample/">backend >></a><br>
<br>
<?php
require './../vendor/autoload.php';
$client = new \GuzzleHttp\Client();
// $response = $client->request('GET', 'https://api.github.com/repos/guzzle/guzzle');
$response = $client->request('GET', 'http://docker_sample_api/');
echo $response->getStatusCode(); // 200
echo '<br>';
echo $response->getHeaderLine('content-type'); // 'application/json; charset=utf8'
echo '<br>';
echo $response->getBody(); // '{"id": 1420053, "name": "guzzle", ...}'
?>
</body>
</html>
frontend/nginx/default.conf
server {
listen 80;
listen [::]:80;
server_name localhost;
root /var/www/html/public;
index index.php index.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# using PHP
# https://gist.github.com/md5/d9206eacb5a0ff5d6be0
#
location ~ [^/]\.php(/|$) {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
if (!-f $document_root$fastcgi_script_name) {
return 404;
}
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
fastcgi_pass php:9000;
fastcgi_index index.php;
}
# using PHP Framework
#
try_files $uri $uri/ @rewrite;
location @rewrite {
rewrite ^(.*)$ /index.php?_url=$1;
}
location ~* ^/(css|img|js|flv|swf|download)/(.+)$ {
root /var/www/html/public;
}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
location ~ /\.ht {
deny all;
}
}
実行する
/etc/hosts
- 存在しないドメインを使う時は /etc/hosts に使用するドメインを追加する。
$ sudo vi /etc/hosts
- 最後の行に今回使用するドメインを追加
- docker.sample
- api.docker.sample
# /etc/hosts
##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting. Do not change this entry.
##
127.0.0.1 localhost
255.255.255.255 broadcasthost
# ::1 localhost
# Added by Docker Desktop
# To allow the same kube context to work on the host and the container:
127.0.0.1 kubernetes.docker.internal
# End of section
127.0.0.1 docker.sample api.docker.sample
インストール
- コンテナを起動する前に事前にインストールしておく
$ cd /path/to/your/frontend/app
$ bin/composer install
コンテナ起動
下記コンテナを全て起動させる。
- nginx-proxy
- backend
- frontend
$ cd /path/to/your/nginx-proxy
$ docker-compose up
$ cd /path/to/your/backend
$ docker-compose up
$ cd /path/to/your/frontend
$ docker-compose up
ネットワークを確認する
「docker_sample_network」というネットワークが作成されている。
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
33da857e13cc bridge bridge local
ff4eb0b291fb docker_sample_network bridge local
2009c1425362 host host local
5eec69202c29 none null local
コンテナを確認する
ネットワークは同じで、
それぞれ別々にコンテナが起動している。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
84b7c82b51e0 backend_app "/docker-entrypoint.…" About a minute ago Up About a minute 80/tcp docker_sample_api
e2cff9d5743f frontend_app "/docker-entrypoint.…" About a minute ago Up About a minute 80/tcp frontend_app_1
9c1f32a55681 php:fpm "docker-php-entrypoi…" 10 minutes ago Up About a minute 9000/tcp frontend_php_1
9b758f0f5077 jwilder/nginx-proxy "/app/docker-entrypo…" 10 minutes ago Up About a minute 0.0.0.0:80->80/tcp nginx-proxy