docker部署的nginx容器访问宿主机端口

6,335 阅读4分钟

这里记录下docker部署的nginx,访问宿主机端口报502的问题,以及解决思路。

一、防火墙

  1. 首先确定宿主机防火墙是否打开了。如果防火墙关闭状态,则容器内应该可以直接访问宿主机的IP+端口。 比如我们的测试环境(Centos 7),防火墙是关闭的。 查看防火墙状态:firewall-cmd --state 或者 systemctl status firewalld 如果显示Active:actice(running) 则表示防火墙为开启状态。

image.png 防火墙关闭状态: image.png 一般测试环境为了方便,直接将防火墙关闭了,这样在我们平时开发和测试的时候,确实会方便一些,但是有时候就是因为防火墙的原因,导致我们的程序在上了生产之后,出现莫名其妙的问题。

明明测试环境就是正常的,怎么生产就不好使了。。。。。。

如果防火墙是开启状态,那么我们就要开放特定的端口了。

firewall-cmd --zone=public --add-port=80/tcp --permanent
--zone #作用域

--add-port=80/tcp  #添加端口,格式为:端口/通讯协议

--permanent   #永久生效,没有此参数重启后失效

重启防火墙:systemctl restart firewalld.service

查看开放端口:

netstat -ntlp

image.png

firewall-cmd --list-ports

image.png

查看端口占用情况:lsof -i:端口号

lsof -i:8000

下面就是nginx的问题了。

二、使用虚拟IP进行容器内核宿主机通信

由于我这里使用的是docker安装的nginx,并且自定义了配置文件。

所以在进行路由转发和配置域名时,直接改配置文件即可。

首先是配置域名,配置域名很简单,只需要按照域名供应商提供的方法,将秘钥和key文件弄出来,然后放到nginx可以访问的路径下,将路径配置到conf的文件里面。

这里贴上现在用的配置,仅供参考,照搬不一定好使。

首先是定义监听80端口的配置文件:default.conf

    upstream cavdWeb {
        server 172.17.0.1:9999;
    }


server {
    listen       80;
    server_name  cavd.org.cn;
    charset utf-8;

    #charset koi8-r;
    #access_log  /var/log/nginx/host.access.log  main;



    location / {
        root   /usr/share/nginx/html;
        index  safety-project/index.html index.htm;
    }

    location /web{
        proxy_pass http://cavdWeb/web;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_redirect default;
    }    

    #location /download/ {
    #    alias /opt/upload/;
    #    autoindex on;
    #}
}

上面定义了一个 upstream cavdWeb 这个玩意就是我们下面进行固定前缀动态代理到别的端口或者IP所用到的。

这里面的IP:172.17.0.1不是宿主机的IP。这点坑了我好久。

这个IP为docker和宿主机通信的IP,是一个虚拟的IP,查询方式是直接看 ifconfig 里的docker0

image.png

如果防火墙是关闭状态,直接写宿主机的IP和端口,可以直接访问,如果防火墙开机状态,则直接nginx启动失败。具体失败的日志可以使用docker logs --since 5m 容器ID 查看,其中 5m表示最近5分钟的日志。

image.png

然后是监听443的配置文件:https.conf


    #upstream cavdWeb {
    #    #server 192.168.5.288:9999;
    #    server 172.17.0.1:9999;
    #}

    server { 
	listen       443 ssl; 
	server_name  www.baidu.com; 
	#ssl                  on; 
	ssl_certificate      /etc/nginx/cert/server.pem; 
	ssl_certificate_key  /etc/nginx/cert/server.key; 
	ssl_session_timeout  5m; 
	ssl_protocols  TLSv1 TLSv1.1 TLSv1.2;
	ssl_ciphers  HIGH:!RC4:!MD5:!aNULL:!eNULL:!NULL:!DH:!EDH:!EXP:+MEDIUM;
        ssl_prefer_server_ciphers   on; 
    location / {
        root   /usr/share/nginx/html;
        index  safety-project/index.html index.htm;
    }

    location /web{
        proxy_pass http://cavdWeb/web;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_redirect default;
    }

} 

其中:

        ssl_certificate      /etc/nginx/cert/server.pem; 
	ssl_certificate_key  /etc/nginx/cert/server.key; 

为存放https证书的路径及文件名。这里的路径需要保证nginx可以访问到。

[warn] the "ssl" directive is deprecated, use the "listen ... ssl" directive instead

如果看到nginx日志里面包含上面的提醒,是因为nginx从1.18版本后,nginx提示ssl这个指令已经不建议使用,要使用listen ... ssl替代。所以看到上面配置文件 ssl on 这行给注释掉了,开头使用 listen 443 ssl

意思就是如果是直接安装的,设置绝对路径即可,如果是docker安装的,需要放在挂载的目录下面,保证nginx可以访问到。

另外,upstream cavdWeb 这个玩意 同一个名称在nginx下面只能定义一次,否则会启动失败。

刚开始我天真的将 upstream cavdWeb 中的地址定义为宿主机的IP或者127.0.0.1就可以了,结果启动之后,访问一直是502 Bad Gayteway,或者可以从日志中看到:host not found in upstream "xxxxxxx"

在搜了半天网上的答案都是,首先看下服务端口是否正常,如果服务关闭了,确实是会出现502的错误。我看到这的时候,就没有想到,服务没开跟服务开了 访问不到,不是一回事么,结果倒腾了半天。。。。。。

最后贴上我的nginx的配置文件:nginx.conf

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
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;
}

这里直接将 /etc/nginx/conf.d路径下的所有conf结尾的配置文件都自动引入了。

启动docker镜像的命令:

docker run --privileged=true \
  --restart=always \
  --name nginx \
  -d -p 80:80 \
  -d -p 443:443 \
  -v /usr/soft/nginx/html:/usr/share/nginx/html \
  -v /usr/soft/nginx/nginx.conf:/etc/nginx/nginx.conf:ro \
  -v /usr/soft/nginx/conf.d:/etc/nginx/conf.d \
  -v /usr/soft/nginx/cert:/etc/nginx/cert \
  -v /opt/upload:/opt/upload \
  192.168.104.51:5000/huaun/nginx:test 

此处用的镜像是在网上找的,然后打了自己的镜像仓库tag。

这里将80和443端口映射出来,然后用-v将需要用到的几个目录挂载出来。