为Docker中运行的服务自动签发证书

Docker的一个强大之处是其及其丰富的生态系统,不仅有各种各样的服务镜像,还有一些有趣实用的工具镜像。

有Docker以前,我们部署一个软件或者服务,需要考虑不同平台的兼容性,需要考虑是不是和服务器已经安装的软件冲突。自从Docker的出现,在很大程度上解决了这些问题。只要软件提供了对应的Docker镜像,我们只需要简简单单一条命令,就可以迅速的安装和使用这个软件,而且也不用考虑平台的差异性以及和其它软件是否会有冲突。甚至,由于Docker的轻量性,我们可以在一台服务器上同时部署多个软件对外提供服务,只需要小心每个容器映射主机的端口不要冲突就行了。

​ 但是我们也知道,HTTP默认的端口是80,HTTPS默认的端口是443,如果我们想让用户不需要指定端口,只通过不同的域名就可以访问到我们同一个服务器上不同Docker容器运行的服务,就需要在宿主机上安装一个Nginx服务,通过nginx的反向代理来将不同的域名反向代理到不同的服务上。

​ 此外,如果我们想使用HTTPS,则必须拥有域名对应的证书。现在最流行的免费证书是Letsencrypt,虽然说证书的有效期只有三个月,但是可以借助Letsencrypt提供的Certbot工具来实现快到期自动续签,不需要担心证书会失效。

​ Docker的一个强大之处是其及其丰富的生态系统,不仅有各种各样的服务镜像,还有一些有趣实用的工具镜像。今天介绍的就是其中的nginx-proxy镜像和acme-companion镜像,这两个镜像配合使用,可以实现自动反向代理容器中运行的服务和自动签发证书,可以说是十分的方便和实用了。

​ 为了演示今天操作的过程,这里我使用了腾讯云轻量服务器,为什么使用腾讯云轻量服务器,首先是因为其性价比非常的高,对于新用户,1核2G的配置只需要99元一年,简直是主机界的一股清流,其次,对使用者也很友好,提供了各种各样的包含docker在内的各种预置镜像,能很快上手使用。

购买服务器

首先,我们需要购买一台腾讯云轻量服务器,点击这里打开购买页面,选择需要的配置、以及地域和时长,镜像选择Docker CE 19.03.9,点击立即购买,等支付完毕后,我们就拥有了自己的第一个云服务器。

新用户购买页面

由于需要使用反向代理和签发证书,因此必须注册一个域名。目前由于大陆的政策原因,使用域名指向香港的服务器需要ICP备案(腾讯云会协助进行备案),备案时间通常在十天左右。如果等不及的话,可以购买轻量云的香港节点进行使用,使用香港节点不需要进行备案。购买香港服务器以及购买域名和设置解析等内容请参考这里

购买成功后,进入到控制台,在轻量应用服务器页面,就可以看到我们有了一台运行中的轻量服务器

轻量服务器

点击上图中的【登录】按钮,会弹出下图这样的一个黑色对话框,我们后面的命令将直接在这个对话框里输入,无需再安装第三方的客户端。

自带web终端

测试环境

在购买服务器的时候,我们选择了Docker CE这个镜像,因此,我们当前服务器里已经有了Docker的环境。而且,轻量云提供的Docker环境已经将docker镜像源替换成了腾讯云自己的Docker镜像源,拉取镜像的速度也是嗖嗖的快。

经测试,下载并解压一个1G左右的镜像,仅需要1分钟左右。和直接使用Docker官方镜像源相比,节省下来的时间可以绕地球跑上三圈了

下载镜像

Docker环境没有问题,下一步就可以启动并运行nginx-proxy容器和acme-companion容器了。

启动nginx-proxy

nginx-proxy容器的作用通过设置反向代理,将别的容器中的服务通过80端口或者443端口暴露在公网上。nginx-proxy容器会监视别的容器的启动,一旦发现别的容器里有VIRTUAL_HOST(指定了Host)和VIRTUAL_PORT(指定了容器中服务监听的端口)这两个环境变量,会自动对其添加相应的反向代理配置中。

首先需要启动nginx-proxy容器。在启动之前,先创建/data/nginx目录。也可以修改这个目录为自己需要的目录。创建好目录以后,就可以输入下面命令来启动nginx-proxy了。

1
2
3
4
5
6
7
8
9
sudo docker run --detach 
    --name nginx-proxy 
    --publish 80:80 
    --publish 443:443 
    --volume /data/nginx/certs:/etc/nginx/certs 
    --volume /data/nginx/vhost:/etc/nginx/vhost.d 
    --volume /data/nginx/html:/usr/share/nginx/html 
    --volume /var/run/docker.sock:/tmp/docker.sock:ro 
    nginxproxy/nginx-proxy

启动以后,如果我们看到下面的文字,说明IPv4 forwarding是禁用状态,需要先把IPv4 forwarding打开,否则,就无法从公网上访问我们的docker容器内的服务了

IPv4 forwarding is disabled. Networking will not work

打开也非常简单,只需要修改/etc/sysctl.conf文件中的net.ipv4.ip_forward,将其值设置为1,然后用下面命令重启网络

1
systemctl restart network

重启网络之后,为了保险起见,最好用sudo docker rm -f nginx-proxy删除掉容器以后,重新启动该容器。

容器启动成功后,可以看到其已经正常运行了

我们可以运行一个服务来简单测试一下nginx-proxy是否像预期那样的工作。

首先,我将grafana.lixf.ink解析到了这台服务器的IP上。对此步有疑问的请参考这里

然后,使用下面命令运行一个grafana。从命令中可以看出,并没有将容器的然和端口映射到宿主机的端口上,只是额外添加了两个环境变量VIRTUAL_HOST和VIRTUAL_PORT来告诉nginx-proxy想使用的域名是grafana.lixf.ink,容器中服务的端口是3000。

1
2
3
4
5
sudo docker run --detach 
    --name grafana 
    --env "VIRTUAL_HOST=grafana.lixf.ink" 
    --env "VIRTUAL_PORT=3000" 
    grafana/grafana

容器启动成功后,在浏览器中访问http://grafana.lixf.in即可访问到grafana。

启动acme-companion

acme-companion容器的作用是自动为域名签发证书,而且还会在证书快到有效期之前自动续发新的证书,从而保证证书永不过期。和nginx-proxy容器一样,acme-companion容器会监视别的容器的启动,一旦发现别的容器里有LETSENCRYPT_HOST(指定了要签发证书的域名)和LETSENCRYPT_EMAIL(指定了邮箱)这两个环境变量,就会为指定的域名签发对应的证书。签发了证书之后,acme-companion容器会自动修改nginx-proxy中相应的配置,使HTTPS和证书生效。

要注意的是,和nginx-proxy不同的是,nginx-proxy不一定非要在公网环境下才能使用,而acme-companion是必须在公网环境中才能使用的。一方面原因是letsencrypt服务器需要通过访问域名来验证域名所有权,另一个更直接的原因是acme-companion无法访问到letsencrypt服务器,就更不用说签发证书了。

好了,啰嗦了这么多,其实运行命令只有下面一条

1
2
3
4
5
6
7
sudo docker run --detach 
    --name nginx-proxy-acme 
    --volumes-from nginx-proxy 
    --volume /var/run/docker.sock:/var/run/docker.sock:ro 
    --volume acme:/etc/acme.sh 
    --env "DEFAULT_EMAIL=326256365@qq.com" 
    nginxproxy/acme-companion

这时候执行docker ps,可以看到我们nginx-proxy和acme-companion在运行了

我们可以运行一个服务来简单测试一下acme-companion是否像预期那样的工作。这里我同时启动grafana和wordpress来进行测试

docker run --detach 
    --name grafana 
    --env "VIRTUAL_HOST=grafana.lixf.ink" 
    --env "VIRTUAL_PORT=3000" 
    --env "LETSENCRYPT_HOST=grafana.lixf.ink" 
    grafana/grafana
    
docker run --detach 
    --name wordpress 
    --env "VIRTUAL_HOST=blog.lixf.ink" 
    --env "VIRTUAL_PORT=80" 
    --env "LETSENCRYPT_HOST=blog.lixf.ink" 
    wordpress

等待两个容器启动成功后,我们可以分别在浏览器中访问grafana.lixf.ink和blog.lixf.ink,可以看到,连个地址都是HTTPS协议了。

小结

本教程借助了腾讯云轻量服务器和nginx-proxy和acme-companion搭建了一个自动为容器服务签发证书的环境,这样,我们后面在使用的时候,只需要指定相应的环境变量,即可以自动拥有安全的小锁标志。现在HTTPS已经是主流,谷歌浏览器不仅对HTTP网站标记为不安全,而且在未来也要默认用户输入的域名使用HTTPS协议。除此之外,HTTPS由于使用了证书签名,也保护了用户的数据安全,防止数据内容被中间人篡改和监听,甚至也防止网站被运营商劫持。从各个方面来看,将网站从HTTP升级为HTTPS都是大势所趋。除了好用的工具以外,选择一个好用的服务器也会有事半功倍的效果。腾讯云轻量服务器自带的Docker镜像可以免除重新安装Docker的过程,而且,价格也是十分的优化,一年99元的价格就可以拥有一台属于自己的服务器。小伙伴们还在等什么呢。

本文来自开发者投稿,不代表腾讯云立场,转载请注明出处:https://computeinit.com/archives/4010

发表评论

登录后才能评论
交流群