如何代理 (容器間如何通信)?
直接使用 nginx 的代理功能即可 (相關(guān)能力另行查閱),這里麻煩的就是 docker 容器間的通信。
docker?容器間通信的主要方式有以下 4 種:
– 通過容器 ip 訪問:容器重啟后,ip 會發(fā)生變化。
– 通過宿主機(jī)的 ip:port 的方式訪問:如果宿主機(jī) ip 改變,就得每個應(yīng)用都得改一遍,并且還要綁定端口,麻煩。
– 通過 link 建立鏈接:相互依賴的太緊,不利于維護(hù)。
– 自定義 network: 在同一個橋接網(wǎng)絡(luò)中的容器可以相互訪問。
很明顯,會選擇 自定義 network 的方式,讓相關(guān)應(yīng)用鏈接到同一個網(wǎng)絡(luò),這樣應(yīng)用與應(yīng)用、代理與被代理之間其實(shí)就沒什么依賴,不僅維護(hù)方便,而且遷移也方便。配置也不麻煩,只需要將常規(guī)的 ip 或域名換成相應(yīng)的容器名即可。
一、統(tǒng)一網(wǎng)絡(luò)
那么,首先需要創(chuàng)建一個共用的橋接網(wǎng)絡(luò):
docker?network?create?proxy-network #?查看 docker?network?ls
?二、代理服務(wù)容器
創(chuàng)建一個專門用來代理的 nginx 服務(wù)容器,取名:proxy-nginx,這里使用 docker-compose 構(gòu)建,其目錄結(jié)構(gòu)最終如下:
proxy-nginx ├──?docker-compose.yml ├──?logs?#?日志 │??└──?error.log ├──?nginx │??├──?dockerfile │??├──?nginx.conf │??└──?startup.sh ├──?sites?#?被代理站點(diǎn)配置 │??├──?baipiaoquan.com.conf │??└──?chaohuahui.com.conf └──?ssl?#?證書文件 ??└──?baipiaoquan.com.pem
有些文件是在后續(xù)的運(yùn)行過程產(chǎn)生的,配置時,只需要把必要的文件和目錄創(chuàng)建好就行。
?docker-compose.yml
version:?"3" networks: ?default: ??external: ???name:?proxy-network services: ?nginx: ??build: ???context:?./nginx ??volumes: ???-?./logs:/var/log/nginx ???-?./sites:/etc/nginx/sites-available ???-?./ssl:/etc/nginx/ssl ??ports: ???-?"80:80" ???-?"443:443"
把對外的 80、443 的端口綁定到代理服務(wù)器,所有的應(yīng)用都可以從這里進(jìn)來。
?dockerfile
from?nginx:alpine label?maintainer="chuoke" copy?nginx.conf?/etc/nginx/ run?apk?update ??&&?apk?upgrade ??&&?apk?add?--no-cache?openssl ??&&?apk?add?--no-cache?bash run?set?-x?; ??addgroup?-g?82?-s?www-data?; ??adduser?-u?82?-d?-s?-g?www-data?www-data?&&?exit?0?;?exit?1 add?./startup.sh?/opt/startup.sh run?sed?-i?'s/.//g'?/opt/startup.sh cmd?["/bin/bash",?"/opt/startup.sh"] expose?80?443
這里將會創(chuàng)建運(yùn)行用戶組和用戶 www-data,方便配置和控制,這個名字會用在 nginx 的配置中。
?nginx.conf
user?www-data; worker_processes?4; pid?/run/nginx.pid; daemon?off; events?{ ?worker_connections?2048; ?multi_accept?on; ?use?epoll; } http?{ ?server_tokens?off; ?sendfile?on; ?tcp_nopush?on; ?tcp_nodelay?on; ?keepalive_timeout?15; ?types_hash_max_size?2048; ?client_max_body_size?20m; ?include?/etc/nginx/mime.types; ?default_type?application/octet-stream; ?access_log?/dev/stdout; ?error_log?/dev/stderr; ?gzip?on; ?gzip_disable?"msie6"; ?ssl_protocols?tlsv1?tlsv1.1?tlsv1.2; ?ssl_ciphers?'ecdhe-ecdsa-chacha20-poly1305:ecdhe-rsa-chacha20-poly1305:ecdhe-ecdsa-aes128-gcm-sha256:ecdhe-rsa-aes128-gcm-sha256:ecdhe-ecdsa-aes256-gcm-sha384:ecdhe-rsa-aes256-gcm-sha384:dhe-rsa-aes128-gcm-sha256:dhe-rsa-aes256-gcm-sha384:ecdhe-ecdsa-aes128-sha256:ecdhe-rsa-aes128-sha256:ecdhe-ecdsa-aes128-sha:ecdhe-rsa-aes256-sha384:ecdhe-rsa-aes128-sha:ecdhe-ecdsa-aes256-sha384:ecdhe-ecdsa-aes256-sha:ecdhe-rsa-aes256-sha:dhe-rsa-aes128-sha256:dhe-rsa-aes128-sha:dhe-rsa-aes256-sha256:dhe-rsa-aes256-sha:ecdhe-ecdsa-des-cbc3-sha:ecdhe-rsa-des-cbc3-sha:edh-rsa-des-cbc3-sha:aes128-gcm-sha256:aes256-gcm-sha384:aes128-sha256:aes256-sha256:aes128-sha:aes256-sha:des-cbc3-sha:!dss'; ?include?/etc/nginx/conf.d/*.conf; ?include?/etc/nginx/sites-available/*.conf; ?open_file_cache?off;?#?disabled?for?issue?619 ?charset?utf-8; }
這個的內(nèi)容拷貝 nginx 的默認(rèn)就行,需要改的就是運(yùn)行用戶名,注意用戶名要和前面的設(shè)置的保持一致。
?startup.sh
#!/bin/bash #?start?crond?in?background crond?-l?2?-b #?start?nginx?in?foreground nginx
這個是用來啟動 nginx 程序用的,內(nèi)容目前比較少,主要是為以后擴(kuò)充內(nèi)容方便。
?啟動代理服務(wù)容器
docker-compose?up?-d?nginx
?查看啟動是否正常 docker-compose ps ,如果不正常,檢查下配置是否有錯誤。
這個就這樣,先放著,去創(chuàng)建應(yīng)用。
?三、添加應(yīng)用
添加一個站點(diǎn) https://baipiaoquan.com/。
?配置應(yīng)用容器
同樣使用 docker-compose 創(chuàng)建應(yīng)用。
這是一個 php 項(xiàng)目,所以這個應(yīng)用里至少需要 nginx 和 php-fpm 兩個服務(wù)容器,項(xiàng)目目錄結(jié)構(gòu)如下:
baipiaoquan/ ├──?docker-compose.yml ├──?log │??└──?nginx │????└──?error.log ├──?nginx │??├──?dockerfile │??├──?log │??├──?nginx.conf │??├──?sites │??│??└──?baipiaoquan.com.conf │??├──?ssl │??│??├──?baipiaoquan.com.key │??│??├──?baipiaoquan.com.pem │??└──?startup.sh └──?php-fpm ??├──?dockerfile ??└──?php.ini
docker-compose.yml
version:?'3' networks: ?proxy: ??external: ????name:?${proxy_network_name} ?backend: ??driver:?${networks_driver} services: ?php-fpm: ???build: ????context:?./php-fpm ???volumes: ????-?./php-fpm/php.ini:/usr/local/etc/php/php.ini ????-?${app_code_path_host}:${app_code_path_container}${app_code_container_flag} ???networks: ????-?backend ?nginx: ???build: ????context:?./nginx ????args: ?????-?php_upstream_container=${nginx_php_upstream_container} ?????-?php_upstream_port=${nginx_php_upstream_port} ???volumes: ????-?${app_code_path_host}:${app_code_path_container}${app_code_container_flag} ????-?./log:/var/log/nginx ????-?./sites:/etc/nginx/sites-available ????-?./ssl:/etc/nginx/ssl ???container_name:?${compose_project_name}_nginx ???depends_on: ????-?php-fpm ???networks: ????-?proxy ????-?backend
為了方便調(diào)整,這里使用了環(huán)境變量。
注意 nginx 的容器名稱 container_name: ${compose_project_name}_nginx,這個值很關(guān)鍵并且會在后續(xù)代理中用到。
.env
#?宿主機(jī)中代碼的位置 app_code_path_host=../ #?容器中代碼的位置 app_code_path_container=/var/www #?這個是抄的?laradock app_code_container_flag=:cached #?選擇機(jī)器上的存儲路徑。適用于所有儲存系統(tǒng) data_path_host=~/.baipiaoquan/data ###?drivers?################################################ #?all?volumes?driver? volumes_driver=local? #?網(wǎng)絡(luò)驅(qū)動? networks_driver=bridge? #?代理網(wǎng)絡(luò)名稱,這是前面創(chuàng)建的? proxy_network_name=proxy-network ###?docker?compose?files?################################## #? compose_file=docker-compose.yml #?change?the?separator?from?:?to?;?on?windows compose_path_separator=: #?項(xiàng)目名稱 compose_project_name=baipiaoquan
使用的代理網(wǎng)絡(luò)名稱是:proxy-network,這是在前面創(chuàng)建的;
nginx 的容器名稱會是:baipiaoquan_nginx。
nginx 的 dockerfile
這個文件可以把前面的那個直接拿來,然后加上關(guān)于 php 相關(guān)的就行了。
from?nginx:alpine copy?nginx.conf?/etc/nginx/ run?apk?update ??&&?apk?upgrade ??&&?apk?--update?add?logrotate ??&&?apk?add?--no-cache?openssl ??&&?apk?add?--no-cache?bash run?set?-x?; ??addgroup?-g?82?-s?www-data?; ??adduser?-u?82?-d?-s?-g?www-data?www-data?&&?exit?0?;?exit?1 arg?php_upstream_container=php-fpm arg?php_upstream_port=9000 #?set?upstream?conf?and?remove?the?default?conf run?echo?"upstream?php-upstream?{?server?${php_upstream_container}:${php_upstream_port};?}"?>?/etc/nginx/conf.d/upstream.conf ??&&?rm?/etc/nginx/conf.d/default.conf add?./startup.sh?/opt/startup.sh run?sed?-i?'s/.//g'?/opt/startup.sh cmd?["/bin/bash",?"/opt/startup.sh"] expose?80?443
php-fpm 的 dockerfile
from?php:7.3-fpm arg?puid=1000 env?puid?${puid} arg?pgid=1000 env?pgid?${pgid} run?groupmod?-o?-g?${pgid}?www-data?&& ??usermod?-o?-u?${puid}?-g?www-data?www-data expose?9000 workdir?/var/www cmd?["php-fpm"]
別忘了 php.ini 文件,也可以使用它默認(rèn)的,那就要把這個相關(guān)的配置刪掉。
?服務(wù) baipiaoquan.com.conf 的配置
server?{ ??listen?80?default_server; ??#?for?https ??listen?443?ssl?default_server; ??ssl_certificate?/etc/nginx/ssl/3243258_baipiaoquan.com.pem; ??ssl_certificate_key?/etc/nginx/ssl/3243258_baipiaoquan.com.key; ??ssl_session_timeout?5m; ??ssl_protocols?tlsv1?tlsv1.1?tlsv1.2; ??ssl_ciphers?ecdhe-rsa-aes128-gcm-sha256:high:!anull:!md5:!rc4:!dhe;? ??ssl_prefer_server_ciphers?on; ??add_header?x-frame-options?"sameorigin"; ??add_header?x-xss-protection?"1;?mode=block"; ??add_header?x-content-type-options?"nosniff"; ??#?localhost?一定要 ??server_name?localhost?baipiaoquan.com?www.baipiaoquan.com; ??root?/var/www/;?#?這個和前面的配置保持一致 ??index?index.php?index.html?index.htm; ??location?/?{ ?????try_files?$uri?$uri/?/index.php$is_args$args; ??} ??location?~?.php$?{ ????try_files?$uri?/index.php?=404; ????fastcgi_pass?php-upstream;?#?這個是?nginx?dockerfile?里配置的 ????fastcgi_index?index.php; ????fastcgi_buffers?16?16k; ????fastcgi_buffer_size?32k; ????fastcgi_param?script_filename?$document_root$fastcgi_script_name; ????#fixes?timeouts ????fastcgi_read_timeout?600; ????include?fastcgi_params; ??} ??location?~?/.ht?{ ????deny?all; ??} ??location?/.well-known/acme-challenge/?{ ????root?/var/www/letsencrypt/; ????log_not_found?off; ??} }
我這里算是配全了,其實(shí)可以精簡,只需要配置需要的即可。
?啟動應(yīng)用
此時,已經(jīng)可以啟動 baipiaoquan.com 的服務(wù)了,在 baipiaoquan 的目錄下運(yùn)行:
docker-compose?up?-d?nginx
如果沒有意外,應(yīng)用應(yīng)該啟動并可以接收服務(wù)。亦可以測試下,進(jìn)入容器訪問下 localhost,看看結(jié)果是不是想要的。我是這樣測試的:
docker-compose?exec?nginx?wget?localhost
然后產(chǎn)看返回的數(shù)據(jù)大小,根據(jù)情況判斷是不是成功了。
可以通過下面的命令查看該應(yīng)用是否成功連接到 proxy-network:
docker?network?inspect?proxy-network
接下來要讓全世界的人都能訪問到這個應(yīng)用。
添加代理配置到 nginx-proxy
注意:要先啟動應(yīng)用,然后再開始代理,不然會出現(xiàn) nginx 找不到 upstream 報(bào)錯。
存放位置:proxy-nginx/sites/baipiaoquan.com.conf,只需要把上面的配置拷貝下來,改幾個地方就行,最終配置如下:
#?我這配的僅支持?https,如果沒要求,這個就不需要? server?{ ??listen?80; ??server_name?baipiaoquan.com?www.baipiaoquan.com; ??return?301?https://$host$request_uri;? } server?{ ??#?如果是?http?就配置這個 ??#?listen?80?default_server; ??#?如果是?https?就配置這個 ??listen?443?ssl; ??ssl_certificate??????/etc/nginx/ssl/3243258_baipiaoquan.com.pem; ??ssl_certificate_key????/etc/nginx/ssl/3243258_baipiaoquan.com.key; ??ssl_session_timeout????5m; ??ssl_protocols???????tlsv1?tlsv1.1?tlsv1.2; ??ssl_ciphers????????ecdhe-rsa-aes128-gcm-sha256:ecdhe:ecdh:aes:high:!null:!anull:!md5:!adh:!rc4; ??ssl_prefer_server_ciphers?on; ??server_name?baipiaoquan.com?www.baipiaoquan.com; ??add_header?x-frame-options?"sameorigin"; ??add_header?x-xss-protection?"1;?mode=block"; ??add_header?x-content-type-options?"nosniff"; ??location?/?{ ????proxy_set_header?host????????$host; ????proxy_set_header?x-real-ip??????$remote_addr; ????proxy_set_header?x-forwarded-for???$proxy_add_x_forwarded_for; ????proxy_set_header?x-forwarded-proto??$scheme; ????proxy_set_header?x-forwarded-host??$host; ????proxy_set_header?x-forwarded-port??$server_port; ????proxy_pass?http://baipiaoquan_nginx/;?#?這個值就是應(yīng)用?nginx?的容器名稱 ??} }
重新加載代理服務(wù)器的配置,在 nginx-proxy 目錄下運(yùn)行:
#?先測試下配置文件,這步一定要執(zhí)行成功 docker-compose?exec?nginx?nginx?-t #?如果提示成功,則重新加載,否則就按提示檢查修改配置文件 docker-compose?exec?nginx?nginx?-s?reload
稍等片刻,如果一切順利,那么現(xiàn)在全世界的人應(yīng)該能訪問到這個 https://baipiaoquan.com/ 網(wǎng)站了。?
如果還需要添加其他應(yīng)用,是一樣的邏輯,流程照搬。例如我又加了一個應(yīng)用:https://chaohuahui.com/ ,可以 ping 一下他們的 ip 是一樣的。