學習docker為的是部署時能更輕松的解決環境問題,docker啟動nginx相比學習了docker的朋友們基本上都會使用了,但要修改配置檔案或者是部署dist前端項目就會有點麻煩了,如果直接進入容器,你會發現,容器中的環境基本上是一個閹割版的,Linux上的許多指令在容器中是無法使用的,是以這樣是十分麻煩的。好在docker有資料卷挂載技術,但是在啟動nginx時又會遇到一堆的問題。
情景再現:
docker run -d -p 80:80 -v /home/nginx/conf:/etc/nginx -v /home/nginx/html:/usr/share/nginx/html --name nginx01 nginx
輸入上面指令,回車,再使用
docker ps
檢視會發現容器并沒有正在運作:
[[email protected] home]# docker run -d -p 80:80 -v /home/nginx/conf:/etc/nginx -v /home/nginx/html:/usr/share/nginx/html --name nginx01 nginx
d3dd01432c1f0f2deb588deda51503d88048456c62d66a93f40a811a9c68991f
[[email protected] home]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
使用
docker ps -a
檢視發現容器确實有了,但不知道為什麼自動停止了。
[[email protected] home]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d3dd01432c1f nginx "/docker-entrypoint.…" 2 minutes ago Exited (1) 2 minutes ago nginx01
這時使用
docker logs 容器id(或者容器名)
檢視容器日志資訊
[[email protected] home]# docker logs nginx01
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: /etc/nginx/conf.d/default.conf is not a file or does not exist
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2021/01/14 03:24:08 [emerg] 1#1: open() "/etc/nginx/nginx.conf" failed (2: No such file or directory)
nginx: [emerg] open() "/etc/nginx/nginx.conf" failed (2: No such file or directory)
大概意思好像是
/etc/nginx/nginx.conf
沒有這個檔案,這就有點好奇了,理論上運作一個nginx容器是絕對不會沒有配置檔案的,那就有可能是這個目錄指代的不是容器中的目錄。
解決方法:
在docker hub官網上查詢了一下發現以下有用的資訊:

官網這段話的大概意思就是,要給nginx挂載卷,要先有一個配置檔案才能挂載,具體做法就是先以不挂載卷的形式正常啟動一個nginx容器,然後從中
cp
拷貝一份配置檔案,删除這個容器,再重新以挂載卷的形式啟動一個新容器。
先把之前的nginx01容器給删除,然後啟動一個不挂載卷的nginx。
docker run -d -p 80:80 --name nginx-test nginx
[[email protected] home]# docker run -d -p 80:80 --name nginx-test nginx
278ac2479e5a6054cfdfbbd14171556e1a0065ff8b33f788c4f9a4cb72f4af65
[[email protected] home]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
278ac2479e5a nginx "/docker-entrypoint.…" 2 seconds ago Up 2 seconds 0.0.0.0:80->80/tcp nginx-test
[[email protected] home]#
在Linux中使用
curl localhost
檢視是否正常啟動服務,也可以在浏覽器上輸入伺服器或虛拟機ip位址檢視,不過端口一定要檢視是否暴露了。
[[email protected] home]# curl localhost
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
[[email protected] home]#
這樣就說明正常啟動服務了,這個時候就把容器内的配置檔案拷貝一份到本機上,使用
docker cp
指令,不熟悉該指令的可以先使用
docker cp --help
檢視
[[email protected] home]# docker cp --help
Usage: docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-
docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH
Copy files/folders between a container and the local filesystem
Use '-' as the source to read a tar archive from stdin
and extract it to a directory destination in a container.
Use '-' as the destination to stream a tar archive of a
container source to stdout.
Options:
-a, --archive Archive mode (copy all uid/gid information)
-L, --follow-link Always follow symbol link in SRC_PATH
[[email protected] home]#
我們這裡拷貝不需要使用可選參數,先檢視一下目錄情況:
[[email protected] home]# ls
blog_admin ceshi mysql nginx
[[email protected] home]#
nginx目錄是第一次以挂載卷形式啟動出現的,雖然容器啟動就停止,但目錄确确實實生成了,其他目錄是我的本地目錄。使用
rm -rf nginx/
删除nginx目錄:
[[email protected] home]# rm -rf nginx/
[[email protected] home]# ls
blog_admin ceshi mysql
[[email protected] home]#
現在開始執行docker的拷貝指令:
docker cp nginx-test:/etc/nginx /home/nginx/conf
[[email protected] home]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
278ac2479e5a nginx "/docker-entrypoint.…" 7 minutes ago Up 6 minutes 0.0.0.0:80->80/tcp nginx-test
[[email protected] home]# docker cp nginx-test:/etc/nginx /home/nginx/conf
invalid output path: directory "/home/nginx" does not exist
[[email protected] home]#
這說明沒有/home/nginx這個目錄,可以先建立一個目錄,
mkdir nginx
[[email protected] home]# ls
blog_admin ceshi mysql
[[email protected] home]# mkdir nginx
[[email protected] home]# ls
blog_admin ceshi mysql nginx
[[email protected] home]#
然後再執行上面的docker cp指令:
[[email protected] home]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
278ac2479e5a nginx "/docker-entrypoint.…" 9 minutes ago Up 9 minutes 0.0.0.0:80->80/tcp nginx-test
[[email protected] home]# docker cp nginx-test:/etc/nginx /home/nginx/conf
[[email protected] home]# ls
blog_admin ceshi mysql nginx
[[email protected] home]# cd nginx/
[[email protected] nginx]# ls
conf
[[email protected] nginx]# cd conf/
[[email protected] conf]# ls
conf.d fastcgi_params koi-utf koi-win mime.types modules nginx.conf scgi_params uwsgi_params win-utf
[[email protected] conf]#
這樣配置檔案就正常拷貝過來了,把這個nginx-test的容器停止并删除。
[[email protected] conf]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
278ac2479e5a nginx "/docker-entrypoint.…" 12 minutes ago Up 3 seconds 0.0.0.0:80->80/tcp nginx-test
[[email protected] conf]# docker stop nginx-test
nginx-test
[[email protected] conf]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[[email protected] conf]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
278ac2479e5a nginx "/docker-entrypoint.…" 12 minutes ago Exited (0) 5 seconds ago nginx-test
[[email protected] conf]# docker rm nginx-test
nginx-test
[[email protected] conf]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[[email protected] conf]#
然後再使用第一次的挂載卷形式,啟動容器。
[[email protected] conf]# docker run -d -p 80:80 -v /home/nginx/conf:/etc/nginx -v /home/nginx/html:/usr/share/nginx/html --name nginx01 nginx
3ccd5825375603510538fd07b8b39bd9cbb0924881c9b7041e87f702aa379424
[[email protected] conf]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3ccd58253756 nginx "/docker-entrypoint.…" 3 seconds ago Up 2 seconds 0.0.0.0:80->80/tcp nginx01
[[email protected] conf]# curl localhost
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.19.6</center>
</body>
</html>
[[email protected] conf]#
看到403的小夥伴别慌,這其實是正常的啟動了,但因為
/home/nginx/html
目錄下是空的,是以才會出現403,因為此時
/home/nginx/html
對應的是容器中的
/usr/share/nginx/html
目錄,可以進到容器中檢視目錄,如果為空,自然通路80端口服務不會有任何東西了。
[[email protected] conf]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3ccd58253756 nginx "/docker-entrypoint.…" 3 minutes ago Up 3 minutes 0.0.0.0:80->80/tcp nginx01
[[email protected] conf]# docker exec -it nginx01 /bin/bash
[email protected]:/# cd /usr/share/nginx/html
[email protected]:/usr/share/nginx/html# ls
[email protected]:/usr/share/nginx/html#
這個時候隻需要在本地主機目錄的
/home/nginx/html
目錄下放上一個index.html就行了(使用exit指令退出容器):
[[email protected] html]# pwd
/home/nginx/html
[[email protected] html]# ls
[[email protected] html]# touch index.html
[[email protected] html]# ls
index.html
[[email protected] html]# cat index.html
[[email protected] html]# vi index.html
[[email protected] html]# cat index.html
hello world
[[email protected] html]#
這個時候再去通路80端口:
[[email protected] html]# curl localhost
hello world
[[email protected] html]#
以上就完成了docker對nginx的配置檔案的挂載。
如果部署dist前端項目,隻需要把dist檔案夾裡的内容全部拷貝到
/home/nginx/html
下,此時通路80端口,預設就是你的項目,不需要重新開機容器。
重點!!!防止再踩坑:
因挂載卷映射出來的nginx配置檔案,千萬不要配置監聽端口,因為配置了也隻是對nginx容器裡面生效!!!
切記,不要在
/home/nignx/conf
的nginx.conf下進行類似如下的監聽端口配置:
server {
listen 9528;
server_name localhost;
root /usr/share/nginx/html;
location / {
try_files $uri $uri/ @router;
index index.html index.htm;
}
location @router {
rewrite ^.*$ /index.html last;
}
}
如果你進行了這樣的配置,也重新開機了容器,但你會發現仍然無法通過
伺服器ip:端口
的形式通路,無法達到你想要的結果,因為這樣的配置隻在容器中生效:
[[email protected] conf]# pwd
/home/nginx/conf
[[email protected] conf]# ls
conf.d fastcgi_params koi-utf koi-win mime.types modules nginx.conf scgi_params uwsgi_params win-utf
[[email protected] conf]# cat nginx.conf
server {
listen 9528;
server_name localhost;
root /usr/share/nginx/html;
location / {
try_files $uri $uri/ @router;
index index.html index.htm;
}
location @router {
rewrite ^.*$ /index.html last;
}
}
[[email protected] conf]# curl localhost
hello world
[[email protected] conf]# curl localhost:9528
curl: (7) Failed connect to localhost:9528; 拒絕連接配接
[[email protected] conf]#
ps:
在cat nginx.conf指令
為了友善看配置檔案,我把其他的删除,隻顯示增加的配置内容。
而進入容器是可以正常通路9528端口的:
[[email protected] conf]# docker exec -it nginx01 /bin/bash
[email protected]:/# curl localhost
hello world
[email protected]:/# curl localhost:9528
hello world
[email protected]:/#
如果你仍然需要使用9528或者其他端口通路你所部署的項目的話,可以在運作挂載卷的nginx容器中映射端口時不映射80,而是你所想的端口,例如:
docker run -d -p 9528(或者是其他你想達到的端口):80 -v /home/nginx/conf:/etc/nginx -v /home/nginx/html:/usr/share/nginx/html --name nginx01 nginx