目录
引言
一、环境说明
二、问题描述
三、解决方案
3.0 端口详细说明
3.1 检查端口占用情况
① 确认服务端口
② 停止移除占用
3.2 停止移除容器
① 停止移除容器
② 运行新的容器
3.3 处理命名冲突
3.4 启动新的Nginx容器
① 启动容器
② 注意事项
③ 映射其它
3.5 验证服务是否正常工作
四、命令总结
五、本文总结
前言
在现代Web开发中,Docker已经成为部署应用的标准工具之一。它提供了便捷的环境隔离和快速部署的能力,使得开发者能够更加专注于代码本身,而不是服务器配置。这里将围绕如何在Docker环境中部署Nginx服务展开讨论,并详细讲解如何解决遇到的端口映射冲突、配置文件挂载等问题。
一、环境说明
- 操作系统:Linux Ubuntu( 乌班图 )
- Docker版本:最新稳定版
- Nginx配置文件位置:/usr/local/develop/docker-app/nginx/conf/nginx.conf
- 网站根目录位置:/usr/local/develop/docker-app/nginx/html/xz_control
- nginx.conf 配置文件
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
#include /etc/nginx/conf.d/*.conf;
server {
listen 80; # 配置监听的端口
listen [::]:80;
server_name localhost; # 配置的域名
# system one
location / {
root /usr/share/nginx/html/xitong; # 网站根目录
index index.html index.htm; # 默认首页文件
# 前端加载404问题
try_files $uri $uri/ /index.html;
}
location ^~/prod-api/{
proxy_pass http://192.168.110.40:9012/;
}
location ^~/prodpy-api/{
proxy_pass http://192.168.0.43:7777/;
}
}
server {
listen 81; # 配置监听的端口
listen [::]:81;
server_name localhost; # 配置的域名
# system two
location / {
root /usr/share/nginx/html/xz_control; # 网站根目录
index index.html index.htm; # 默认首页文件
# 前端加载404问题
try_files $uri $uri/ /index.html;
}
location ^~/prod-api/{
proxy_pass http://192.168.110.40:9011/;
}
location ^~/prodpy-api/{
proxy_pass http://192.168.0.43:7777/;
}
}
}
这里的nginx.conf文件,配置了两个server
块,分别监听80和81端口。在Docker容器中运行这个配置,并正确地映射主机的端口到容器内的相应端口时,遇到问题。
二、问题描述
在尝试通过Docker运行Nginx服务时,遇到了端口81 已经被其他服务占用的问题,同时发现名为nginx-new的容器名称已被使用,导致无法直接启动新的容器。
三、解决方案
3.0 端口详细说明
端口就像是家里不同房间的门牌号,每个门牌号对应着家里不同的房间。在计算机的世界里,端口就是这样一个概念,它帮助电脑区分不同应用程序或服务的“房间”。总共有65536个这样的“房间”,从0到65535编号。
其中一些“房间”有特别的用途,比如HTTP(超文本传输协议)使用80号端口,这是当你访问一个网站时,默认用来传输网页内容的通道;而HTTPS(安全的超文本传输协议),用于加密和安全地浏览网页,则默认使用443号端口。通过这些特定的端口号,电脑能够准确无误地把数据送到正确的应用程序手中,就像邮递员根据地址把包裹送到正确的家门口一样。这样,无论你是浏览网页、发送邮件还是进行在线聊天,都能顺利进行而不发生混乱。
3.1 检查端口占用情况
① 确认服务端口
首先,我们需要确认哪些服务正在使用81端口
查找占用80端口的进程:
sudo lsof -i :80
查找占用81端口的进程:
sudo lsof -i :81
实际执行和响应(执行成功):
xingdun@xingdun-ThinkStation-P330:~$ sudo lsof -i :81
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
docker-pr 127483 root 4u IPv4 739301 0t0 TCP *:81 (LISTEN)
docker-pr 127491 root 4u IPv6 742405 0t0 TCP *:81 (LISTEN)
从这里的输出可以看到,端口81已经被一个Docker进程(docker-pr
)占用。具体来说,PID为127483和127491的进程正在监听81端口。这意味着您需要停止相关的容器以释放81端口,或者选择将新容器的端口映射到主机上的其他未被占用的端口。
② 停止移除占用
这里来停止并移除占用81端口的容器
首先,需要找出哪个容器正在使用这些端口。该命令会列出所有发布(即映射)了81端口的容器:
docker ps --filter "publish=81"
实际执行和响应(执行成功):
xingdun@xingdun-ThinkStation-P330:~$ docker ps --filter "publish=81"
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
69b39f5df9a5 nginx "/docker-entrypoint.…" 20 minutes ago Up 20 minutes 80/tcp, 0.0.0.0:81->81/tcp, :::81->81/tcp my-nginx
根据响应信息,有一个名为 my-nginx
的容器正在使用81端口。
这里并没有直接的矛盾或额外的冲突。lsof
输出中的 docker-pr
进程是 Docker 内部用于处理端口映射的进程,它们与 docker ps
显示的 my-nginx
容器直接相关。也就是说,正是 my-nginx
容器通过 Docker 的端口映射机制占用了主机的81端口,而 docker-pr
是实现这一映射的进程。
3.2 停止移除容器
停止并移除现有的 my-nginx
容器
如果您不再需要现有的 my-nginx
容器,可以先停止并移除它以释放81端口。
① 停止移除容器
停止并移除现有的 my-nginx
容器
该命令,用于停止一个正在运行的容器,这里表示它将会停止名为 my-nginx
的容器:
docker stop my-nginx
该命令,用于移除一个已经停止的容器,这里表示它将会移除名为 my-nginx
的容器:
docker rm my-nginx
② 运行新的容器
运行新的 nginx-new
容器
docker run --name nginx-new \
-v /usr/local/develop/docker-app/nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro \
-v /usr/local/develop/docker-app/nginx/html/xitong:/usr/share/nginx/html/xitong:ro \
-v /usr/local/develop/docker-app/nginx/html/xz_control:/usr/share/nginx/html/xz_control:ro \
-p 80:80 -p 81:81 \
-d nginx
各参数的作用
docker run
: 运行一个新的容器。--name nginx-new
: 给容器命名为nginx-new
。这使得你可以通过这个名字来引用这个容器,而不是使用其ID。-v /usr/local/develop/docker-app/nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro
: 将主机上的/usr/local/develop/docker-app/nginx/conf/nginx.conf
文件挂载到容器内的/etc/nginx/nginx.conf
路径下,且以只读模式 (ro
) 挂载。这意味着容器会使用你指定的Nginx配置文件而不是默认的配置文件。-v /usr/local/develop/docker-app/nginx/html/xitong:/usr/share/nginx/html/xitong:ro
: 将主机上的/usr/local/develop/docker-app/nginx/html/xitong
目录挂载到容器内的/usr/share/nginx/html/xitong
路径下,同样以只读模式挂载。这样做的目的是让Nginx能够访问你的网站根目录下的内容。-v /usr/local/develop/docker-app/nginx/html/xz_control:/usr/share/nginx/html/xz_control:ro
: 类似地,将另一个网站根目录挂载到容器内相应的路径下。-p 80:80
: 将主机的80端口映射到容器内的80端口。这意味着任何发送到主机80端口的请求都会被转发到容器内的80端口上运行的服务(在这个例子中是Nginx)。-p 81:81
: 同样地,将主机的81端口映射到容器内的81端口,允许外部访问容器内监听在81端口上的服务。-d nginx
: 使用官方的nginx
镜像以后台模式 (detached mode
, 简写为-d
) 启动容器。
这条命令的主要功能包括:
- 创建并命名一个新容器 (
nginx-new
)。 - 挂载自定义的Nginx配置文件 到容器内部,覆盖默认配置。
- 挂载两个不同的网站根目录 到容器内部,以便Nginx可以提供这些网站的内容。
- 设置端口映射,使得可以通过主机的80和81端口访问容器内的Nginx服务。
- 以后台模式启动容器 使用官方的 Nginx 镜像。
通过这种方式,可以利用Docker容器技术,来部署具有特定配置的Nginx服务器,并且可以方便地管理和扩展这种部署方式。
实际执行和响应(执行报错):
xingdun@xingdun-ThinkStation-P330:~$ docker run --name nginx-new \
-v /usr/local/develop/docker-app/nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro \
-v /usr/local/develop/docker-app/nginx/html/xitong:/usr/share/nginx/html/xitong:ro \
-v /usr/local/develop/docker-app/nginx/html/xz_control:/usr/share/nginx/html/xz_control:ro \
-p 80:80 -p 81:81 \
-d nginx
docker: Error response from daemon: Conflict. The container name "/nginx-new" is already in use by container "6f3f3841caae693acf44de52904ee14dcaa6e9e17e0f0b2c37023e3198d9ac49". You have to remove (or rename) that container to be able to reuse that name.
See 'docker run --help'.
从错误信息来看,名为 nginx-new
的容器名称已经被占用。这意味着之前有一个名为 nginx-new
的容器已经存在,即使它可能没有成功启动或者已经被停止了。您需要先处理这个现有的容器,才能使用相同的名字来运行新的容器。
3.3 处理命名冲突
由于存在名为nginx-new
的容器,我们需要先停止移除现有的同名容器。
该命令,用于停止一个正在运行的容器,这里表示它将会停止名为 nginx-new
的容器:
docker stop nginx-new
该命令,用于移除一个已经停止的容器,这里表示它将会移除名为 nginx-new
的容器:
docker rm nginx-new
3.4 启动新的Nginx容器
① 启动容器
接下来,我们可以使用以下命令,来启动一个新的Nginx容器,并正确地挂载配置文件和网站根目录,同时进行端口映射:
docker run --name nginx-new \
-v /usr/local/develop/docker-app/nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro \
-v /usr/local/develop/docker-app/nginx/html/xitong:/usr/share/nginx/html/xitong:ro \
-v /usr/local/develop/docker-app/nginx/html/xz_control:/usr/share/nginx/html/xz_control:ro \
-p 80:80 -p 81:81 \
-d ngin
实际执行和响应(执行成功):
xingdun@xingdun-ThinkStation-P330:~$ docker run --name nginx-new \
-v /usr/local/develop/docker-app/nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro \
-v /usr/local/develop/docker-app/nginx/html/xitong:/usr/share/nginx/html/xitong:ro \
-v /usr/local/develop/docker-app/nginx/html/xz_control:/usr/share/nginx/html/xz_control:ro \
-p 80:80 -p 81:81 \
-d nginx
844f3be41d4d26dcb188e87ca85a4c184a2b83621313f16bb2e381c500c28
这里表示已经成功地运行了新的 Docker 容器 nginx-new
,并且没有出现错误信息。Docker 返回了一个容器 ID (844f3be41d4d26dcb188e87ca85a4c184a41a84e5a2b836f16bb2e381c500c28
),这表明容器已经被正确创建并以后台模式启动。
② 注意事项
-v
参数用于挂载主机上的文件或目录到容器内,ro
表示只读模式。-p
参数用于端口映射,确保外部可以访问容器内的服务。-d
参数表示以后台模式运行容器。
③ 映射其它
还可以选择将新容器的81端口映射到主机上的其他未被占用的端口,例如8081:
docker run --name nginx-new \
-v /usr/local/develop/docker-app/nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro \
-v /usr/local/develop/docker-app/nginx/html/xitong:/usr/share/nginx/html/xitong:ro \
-v /usr/local/develop/docker-app/nginx/html/xz_control:/usr/share/nginx/html/xz_control:ro \
-p 80:80 -p 8081:81 \
-d nginx
3.5 验证服务是否正常工作
在执行 docker run
命令后,Docker 会基于 Nginx 镜像创建并启动一个新的容器,并且该容器会自动运行 Nginx 服务。由于 -d
参数的作用,这个容器会在后台运行。因此,在正常情况下,执行完这条命令后不需要手动重启 Nginx。启动容器后,可以通过浏览器输入 IP + 81 端口进行访问:192.168.xxx.40:81前端系统页面。
不过,有几种情况可能需要重新加载或重启 Nginx:
① 配置文件更新
如果您修改了挂载到容器内的 Nginx 配置文件(例如 /usr/local/develop/docker-app/nginx/conf/nginx.conf
),则需要让 Nginx 重新加载配置。可以通过以下命令进入正在运行的容器,并发送重载信号:
docker exec nginx-new nginx -s reload
这条命令会让 Nginx 重新加载配置文件而不停止服务。
运行结果如果是
[notice] 42#42: signal process started
:这是 Nginx 日志中的一个通知消息,表示它已经收到重新加载信号,并且已经开始处理该请求。这里的 42#42
指的是进程ID和工作进程ID,表明哪个进程正在处理此操作。
② Nginx 容器停止或异常退出
如果容器内的 Nginx 服务因某种原因停止了,您可以重启整个
docker restart nginx-new
这将重启容器及其内部的所有服务,包括 Nginx。
③ 验证 Nginx 是否正常工作
如果您想检查 Nginx 是否正确地启动并且没有遇到任何错误,可以查看容器的日志:
docker logs nginx-new
如果发现有任何错误信息,根据错误提示进行相应的修正可能是必要的。
注意这里的nginx-new是容器名称。
四、命令总结
为了便于理解和应用每条命令的作用,这里来总结并排序
1. 查看端口占用情况
sudo lsof -i :81
查看81端口使用情况。
2. 列出占用指定端口的容器
docker ps --filter "publish=81"
查找使用81端口的容器。
3. 停止指定容器
docker stop my-nginx
停止名为my-nginx
的容器。
4. 移除指定容器
docker rm my-nginx
删除名为my-nginx
的容器。
5. 运行新的Nginx容器
docker run --name nginx-new \
-v /usr/local/develop/docker-app/nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro \
-v /usr/local/develop/docker-app/nginx/html/xz_control:/usr/share/nginx/html/xz_control:ro \
-p 81:81 \
-d nginx
启动新Nginx容器并映射端口。
6. 运行新容器并映射到不同端口
docker run --name nginx-new \
-v /usr/local/develop/docker-app/nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro \
-v /usr/local/develop/docker-app/nginx/html/xz_control:/usr/share/nginx/html/xz_control:ro \
-p 8081:81 \
-d nginx
映射至未占用端口(如8081)。
7. Nginx 容器停止或异常退出
docker restart nginx-new
重启容器及其内部的所有服务。
8. 重新加载 Nginx 配置
docker exec nginx-new nginx -s reload
重新加载Nginx配置文件,只针对 Nginx。
这些命令覆盖了从检查端口占用、管理Docker容器、到调试和维护Nginx服务的全过程。希望对你有所帮助!
五、本文总结
通过上述步骤,我们成功解决了Docker中部署Nginx服务时遇到的端口映射冲突问题。同时,我们也学会了,如何正确挂载配置文件和网站根目录,确保服务按照预期运行。希望这里能帮助到同样面临这些问题的你。如果有任何疑问或需要进一步的帮助,请随时留言交流!