本部分主要根据IDEA的Docker插件实战(Dockerfile篇)_程序员欣宸的博客-CSDN博客_idea编写dockerfile一文所述内容进行实践,并对其中遇到的问题进行解答,从而串接多个知识点。
在Intellij中,Dockfile只能自己创建并编写,并没有什么工具会帮你自动生成,这一点和.NET平台下的工具不同,需要注意。Dockfile的编写主要是了解语法,还需要选择合适的基础镜像。语法课参考这篇文章:
Docker Dockerfile | 菜鸟教程 (runoob.com)
镜像选择需要自行前往Dockerhub进行镜像查找,网址为:
Docker Hub Container Image Library | App Containerization
docker image是什么,存储在什么位置。 - chinaxuzw的日志 About云开发-梭伦科技 - (aboutyun.com)
Docker镜像分层 - 知乎 (zhihu.com)
在上述文章中详细解释了Docker中镜像是如何分层、如何构建的,理解了这些也就明白了为什么Dockfile中要尽可能少些语句或多条语句合并成一条语句,都是为了降低打包后的镜像大小。
如果按照前言中文章的指南一步步操作,应该不会有其他问题,除了显示的时区不对。时区不对的根源是容器中的时区为UTC,宿主机时间为CST,相差了8小时。具体方法参考:
Docker容器时间与宿主机时间不一致的问题 - 人艰不拆_zmc - 博客园 (cnblogs.com)
这里边可能会涉及进入容器的问题,因为本文使用的基础镜像为alpine,进入容器不是正常的/bin/bash
,而是进入/bin/sh
。
VS对Docker的支持仅限于.NET Core项目,这一点需要留意。VS中的Docker插件功能和IDEA中完全不一样:VS要求当前主机必须安装Docker,制作的镜像只推送到本机的Docker。而VS的使用者大多数都用的是Windows系统,这就意味着当前主机得开启一套虚拟环境以运行Windows版本的Docker,大概需要2G的内存占用。IDEA充分利用了Docker的远程访问功能,所以对本机的要求很低。VS中也可以把镜像打包后推送到远程Docker服务器,但是需要开启服务器Docker的Registry功能,相当于得部署一套私有的Docker仓库。
在创建.NET Core工程时,如果勾选了Docker支持,那么VS会自动创建Dockfile。当然如果项目创建初期没有添加,后面也可以通过右击工程,选择“添加”,再选择“添加Docker”支持来创建(如果没有该选项,大概率是安装VS的时候少勾选了相关容器组件)。如果对Docker很熟悉,也可以完全自行创建,当然最好是先利用VS创建一个基础的Dockfile,然后自行添加或删除一些内容。
所谓的Registry功能就是在服务器上使用Docker官方提供的Registry镜像创建一个容器,外部程序通过HTTP/HTTPS协议和Registry容器交互,从而推送或拉取镜像。创建步骤可以参考该链接:
部署注册表服务器| Docker文档 (xy2401.com)
上步所述的操作可以让本机的应用程序推送镜像,但如果希望外部系统也能操作,那么就需要进行相关配置。如果是有域名证书的伙伴,那么配置外部访问非常容易,直接参照上节的链接描述来做就行。但是很多情况下我们是局域网操作,只想通过HTTP协议访问Registry,那么我们在远程服务器上创建容器时就不能指定证书,同时客户端的机器上需要添加对该远程Docker的信任,具体可参考:
测试不安全的注册表| Docker文档 (xy2401.com)
以上内容简单解释一下。先使用下述指令创建Registry服务:
# 创建不指定证书的容器,同时无用户名密码验证
docker run -d -p 5000:5000 --restart=always --name registry registry:2
# 登陆服务器上的容器
docker login http://192.168.x.x:5000
# 推送容器
docker push NAME[:TAG]
运行此条指令后创建的registry容器就是不指定证书的,此时外部系统可以通过访问http://192.168.x.x:5000来操作该容器,而且无需用户名和密码。
那么如果我想要添加用户名和密码呢?这时候就需要配置TLS,开启服务器认证:
# 首先创建自签名证书
mkdir -p certs
openssl req \
-newkey rsa:4096 -nodes -sha256 -keyout certs/domain.key \
-x509 -days 365 -out certs/domain.crt
# 接着创建需要指定证书的容器
docker run -d \
--restart=always \
--name registry \
-v "$(pwd)"/certs:/certs \
-e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
-p 443:443 \
registry:2
通过以上操作,服务端算是配置好了,所有的访问请求必须通过HTTPS协议,服务端收到请求后把自签名证书发给客户端。
这时候问题就来了,因为是自签名证书,客户端不认,会报错,所以需要客户端信任该证书。
如果客户端是Windows系统,信任证书很容易操作:将服务器上的domain.crt文件拷贝到客户端,直接双击安装证书,下面贴几张安装证书的图。
请务必按照上图的方式导入到“根证书颁发机构”,否则客户端还是无法进行证书认证!此时通过下述指令便可登陆成功:
# 服务端容器使用的是HTTPS协议默认的443端口,所以这里就不需要指定端口了
docker login 192.168.x.x
如果客户端是Linux主机,需要将服务器的证书文件服务到当前主机的/etc/docker/certs.d/myregistrydomain.com:443/
目录下,在这里myregistrydomain.com
就是192.168.x.x。
服务端启用用户名密码验证的前提是已经配置了HTTPS访问,所以这一步写在最后:
# 创建用户名为testuser、密码为testpassword的文件,使用bcrypt加密
mkdir auth
docker run \
--entrypoint htpasswd \
registry:2 -Bbn testuser testpassword > auth/htpasswd
# 创建需要进行访问认证的容器
docker run -d \
-p 443:443\
--restart=always \
--name registry \
-v "$(pwd)"/auth:/auth \
-e "REGISTRY_AUTH=htpasswd" \
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
-e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
-v "$(pwd)"/certs:/certs \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
registry:2
和上一节相比,本节创建容器的过程多了3个变量用于开启访问认证。这里有必要解释下第一步创建认证文件的意图。
htpasswd
是一个创建认证文件的组件,可以在宿主机上直接安装该组件,也可以像Docker官方提供的文档中介绍的那样,通过创建一个htpasswd
的容器并运行来创建认证文件。注意这里传入的参数是-B
,也就是使用bcrypt加密,加密强度更高。如果不加,默认就是MD5加密。Registry组件内部使用的是bcrypt加密方式,所以创建认证文件必须传入-B
参数。
有了认证文件,在创建容器时就需要指定认证文件的地址,因此需要将宿主机的带有认证文件的目录挂载到容器上。此时再登陆Docker,就需要以下指令:
# 在命令行显示输入密码会看到一个Docker返回的Warnning,在意的话不要加入-p
docker login 192.168.x.x -u testuser -p testpassword
以上扯了那么多的主要原因还是VS下的Docker插件不好用,而且使用发布功能推送镜像时必须通过HTTPS访问。那下面来看看如何推送镜像:
顺利的话,我们会看到VS提示镜像已上传成功。如何确认服务器上的确有镜像呢?
curl -XGET -u testuser:testpassword https://192.168.x.x:443/v2/_catalog
笔者自己有个威联通的NAS,且具备公网访问条件,所以冒出了个想法,就是在自己的NAS上部署Docker私库。虽然笔者对部署私库已了然于胸,但在NAS上部署时还是踩了很多坑,如果大家感兴趣,我将再写一篇文章来介绍威联通NAS上如何部署私库。