docker私有仓库搭建
虚拟机环境
hostname命令进行临时更改vm主机名
机器名 | IP 和功能 |
---|---|
docker-registry | 192.168.195.128,docker私有仓库服务器 |
docker-app | 192.168.195.132,运行docker服务的普通服务器 |
配置镜像加速器(阿里云)
参考文档:https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://zu2vm5z6.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
安装私有仓库
执行以下命令,会启动一个registry容器,该容器用于提供私有仓库的服务:
[root@docker-registry docker]# docker run --name docker-registry -d -p 5000:5000 registry
Unable to find image 'registry:latest' locally
latest: Pulling from library/registry
c87736221ed0: Pull complete
1cc8e0bb44df: Pull complete
54d33bcb37f5: Pull complete
e8afc091c171: Pull complete
b4541f6d3db6: Pull complete
Digest: sha256:8004747f1e8cd820a148fb7499d71a76d45ff66bac6a29129bfdbfdc0154d146
Status: Downloaded newer image for registry:latest
f632a793ed4d97c633daf4d18862b8cdede9f340c24e158588c4d2cc18bf733d
[root@docker-registry docker]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f632a793ed4d registry "/entrypoint.sh /etc…" 4 minutes ago Up 4 minutes 0.0.0.0:5000->5000/tcp docker-registry
这将使用官方的registry镜像来启动私有仓库。默认情况下,仓库会被创建在容器的/var/lib/registry目录下。你可以通过 -v 参数来将镜像文件存放在本地的指定路径。–restart=always当 Docker 重启时,容器自动启动。例如下面的例子将上传的镜像放到本地的 /opt/data/registry 目录。
$ docker run -d \
-p 5000:5000 \
-v /opt/data/registry:/var/lib/registry \
--restart=always \
registry
容器正常启动,对外提供服务通过5000端口映射到docker-registry的5000端口;
执行命令curl -X GET http://127.0.0.1:5000/v2/_catalog,收到的响应如下,是个json对象,其中repositories对应的值是空的json数组,表示目前仓库里还没有镜像:
[root@docker-registry docker]# curl -X GET http://127.0.0.1:5000/v2/_catalog
{"repositories":[]}
在私有仓库上传、搜索、下载镜像
[root@docker-app docker]# docker pull tomcat
Using default tag: latest
latest: Pulling from library/tomcat
146bd6a88618: Pull complete
9935d0c62ace: Pull complete
db0efb86e806: Pull complete
e705a4c4fd31: Pull complete
3d3bf7f7e874: Pull complete
49371c5b9ff6: Pull complete
e7873a7ca0fd: Pull complete
925a95344b57: Pull complete
0448a86618da: Pull complete
71917b8caada: Pull complete
Digest: sha256:f8edbcba564eca1d3d6d5d73d993a661801b5a7c6542dff44bdab57d0bccc567
Status: Downloaded newer image for tomcat:latest
docker.io/library/tomcat:latest
创建好私有仓库之后,就可以使用docker tag来标记一个镜像,然后推送它到仓库。例如私有仓库地址为 http://192.168.195.128:5000。先在本机查看已有的镜像。
tomcat latest ed94f55483b8 Less than a second ago 507MB
使用docker tag将 ubuntu:latest 这个镜像标记为 192.168.195.128:5000/ubuntu:latest。 格式为 docker tag IMAGE[:TAG] [REGISTRY_HOST[:REGISTRY_PORT]/]REPOSITORY[:TAG]
[root@docker-app docker]# docker tag ed94f55483b8 192.168.195.128:5000/tomcat
[root@docker-app docker]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
192.168.195.128:5000/tomcat latest ed94f55483b8 Less than a second ago 507MB
tomcat latest ed94f55483b8 Less than a second ago 507MB
先删除已有镜像,再尝试从私有仓库中下载这个镜像。
[root@docker-app ~]# docker rmi 192.168.195.128:5000/tomcat
Untagged: 192.168.195.128:5000/tomcat:latest
Untagged: 192.168.195.128:5000/tomcat@sha256:a20a17236a2393610637906ad3f0d05c260a8bd665b065ca3d09385971cd7eba
[root@docker-app ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat latest ed94f55483b8 Less than a second ago 507MB
[root@docker-app ~]# docker pull 192.168.195.128:5000/tomcat
Using default tag: latest
latest: Pulling from tomcat
Digest: sha256:a20a17236a2393610637906ad3f0d05c260a8bd665b065ca3d09385971cd7eba
Status: Downloaded newer image for 192.168.195.128:5000/tomcat:latest
192.168.195.128:5000/tomcat:latest
[root@docker-app ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
192.168.195.128:5000/tomcat latest ed94f55483b8 Less than a second ago 507MB
tomcat latest ed94f55483b8 Less than a second ago 507MB
注意事项
如果你不想使用 127.0.0.1:5000 作为仓库地址,比如想让本网段的其他主机也能把镜像推送到私有仓库。你就得把例如 192.168.199.100:5000 这样的内网地址作为私有仓库地址,这时你会发现无法成功推送镜像。
这是因为 Docker 默认不允许非 HTTPS 方式推送镜像。我们可以通过 Docker 的配置选项来取消这个限制。
Ubuntu 16.04+, Debian 8+, centos 7
对于使用 systemd 的系统,请在/etc/docker/daemon.json中写入如下内容(如果文件不存在请新建该文件)
[root@docker-app ~]# cat /etc/docker/daemon.json
{
"registry-mirrors": ["https://zu2vm5z6.mirror.aliyuncs.com"],
"insecure-registries":["192.168.195.128:5000"]
}
##注意:该文件必须符合json规范,否则 Docker 将不能启动。
自签发证书(https)
docker官方文档:https://docs.docker.com/registry/deploying/
registry的域名为:https://myregistry.domain.com/
- 生成自签发证书。
mkdir -p certs
openssl req -newkey rsa:2048 -nodes -sha256 -keyout certs/domain.key -x509 -days 365 -out certs/domain.crt
- 启动registry容器
docker run -d \
--restart=always \
--name registry \
-v /opt/data/registry/:/var/lib/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
- 添加域名解析
[root@docker-registry ~]# cat /etc/hosts
192.168.195.128 myregistry.domain.com
- 创建dockerTSL认证证书
cd /etc/docker/
mkdir certs.d/myregistry.domain.com ##创建dockerTSL认证证书
cd certs.d/myregistry.domain.com
cp /root/certs/domain.crt ca.crt ##复制认证证书到当前文件,并改名
systemctl restart docker ##重启docker服务,由于重新加入认证证书
5、测试上传镜像
[root@docker-registry ~]# docker load -i /tmp/mysql.tar
605f8f2fe1e5: Loading layer [==================================================>] 338.4kB/338.4kB
4dac9b6b28ce: Loading layer [==================================================>] 10.44MB/10.44MB
1a527f11e03e: Loading layer [==================================================>] 4.472MB/4.472MB
cee57cdf5101: Loading layer [==================================================>] 1.536kB/1.536kB
76db703007bc: Loading layer [==================================================>] 46.15MB/46.15MB
6b5c7baa4da8: Loading layer [==================================================>] 34.3kB/34.3kB
b4490bc5b370: Loading layer [==================================================>] 3.584kB/3.584kB
15669f7521b3: Loading layer [==================================================>] 350.3MB/350.3MB
b7a46f8264c1: Loading layer [==================================================>] 5.632kB/5.632kB
c1f58dc402c7: Loading layer [==================================================>] 15.87kB/15.87kB
cdae83e68539: Loading layer [==================================================>] 1.536kB/1.536kB
Loaded image: mysql:latest
[root@docker-registry ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mysql latest 791b6e40940c Less than a second ago 465MB
registry latest f32a97de94e1 9 months ago 25.8MB
[root@docker-registry ~]# docker tag mysql:latest 192.168.195.128:443/mysql:latest
[root@docker-registry ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
192.168.195.128:443/mysql latest 791b6e40940c Less than a second ago 465MB
mysql latest 791b6e40940c Less than a second ago 465MB
registry latest f32a97de94e1 9 months ago 25.8MB
[root@docker-registry ~]# docker push 192.168.195.128:443/mysql
The push refers to repository [192.168.195.128:443/mysql]
Get https://192.168.195.128:443/v2/: x509: cannot validate certificate for 192.168.195.128 because it doesn't contain any IP SANs
[root@docker-registry ~]# docker tag mysql:latest myregistry.domain.com/mysql:latest
[root@docker-registry ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
192.168.195.128:443/mysql latest 791b6e40940c Less than a second ago 465MB
mysql latest 791b6e40940c Less than a second ago 465MB
myregistry.domain.com/mysql latest 791b6e40940c Less than a second ago 465MB
registry latest f32a97de94e1 9 months ago 25.8MB
[root@docker-registry ~]# docker push myregistry.domain.com/mysql
The push refers to repository [myregistry.domain.com/mysql]
cdae83e68539: Pushed
c1f58dc402c7: Pushed
b7a46f8264c1: Pushed
15669f7521b3: Pushed
b4490bc5b370: Pushed
6b5c7baa4da8: Pushed
76db703007bc: Pushed
cee57cdf5101: Pushed
1a527f11e03e: Pushed
4dac9b6b28ce: Pushed
605f8f2fe1e5: Pushed
e0db3ba0aaea: Pushed
latest: digest: sha256:283caa87ee6a3997b32beaff33e75974fd689edfd2df0084a45e300d8a001c91 size: 2828
用户认证(基于TSL加密):
创建私有仓库的用户和密码
[root@docker-registry /]# mkdir auth
[root@docker-registry /]# docker run --rm --entrypoint htpasswd registry -Bbn admin 123456 > auth/htpasswd
[root@docker-registry /]# ll /auth/htpasswd
-rw-r--r--. 1 root root 68 2月 4 14:14 /auth/htpasswd
[root@docker-registry /]# cat /auth/htpasswd
admin:$2y$05$G1F3CqnV9W/ZQRVhsDWc5.7F6LqOcaYgz0cBseXF4POfc1wUlSH.6
重新启动registry容器
[root@docker-registry /]# docker run -d \
> --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 /opt/data/registry/:/var/lib/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
2d8837877ca8e381a776a9a58513fd90004fb78194e8e95a6afa2daa92de7f8e
[root@docker-registry /]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2d8837877ca8 registry "/entrypoint.sh /etc…" 3 seconds ago Up 2 seconds 0.0.0.0:443->443/tcp, 5000/tcp registry
验证测试,一开始没有登录认证,push镜像到私有仓库提示报错
[root@docker-registry /]# docker push myregistry.domain.com/httpd
The push refers to repository [myregistry.domain.com/httpd]
3f8d3a1c8148: Preparing
e02e6276ec45: Preparing
b99a0f549e6c: Preparing
36e69e3e1c8c: Preparing
488dfecc21b1: Preparing
no basic auth credentials
登录认证后再push镜像
[root@docker-registry /]# docker login myregistry.domain.com
Username: admin
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
[root@docker-registry /]# docker push myregistry.domain.com/httpd
The push refers to repository [myregistry.domain.com/httpd]
3f8d3a1c8148: Pushed
e02e6276ec45: Pushed
b99a0f549e6c: Pushed
36e69e3e1c8c: Pushed
488dfecc21b1: Pushed
latest: digest: sha256:1e0cddb4e8282099b384d44232e1edc1eb91c033d774f432f3f68dd7b193b3b1 size: 1367
客户端登录认证后再push镜像,login认证失败,这里需要注意:如果使用自签署的证书,那么所有要与Registry交互的Docker主机都需要安装registry.domain.com的ca.crt(domain.crt)。但如果你使用知名CA,这一步也就可以忽略。
[root@docker-app ~]# docker login myregistry.domain.com
Username: admin
Password:
Error response from daemon: Get https://myregistry.domain.com/v2/: x509: certificate signed by unknown authority
[root@docker-app ~]# docker login myregistry.domain.com
[root@docker-app ~]# ll /etc/docker/certs.d/myregistry.domain.com/ca.crt
-rwxr-xr-x. 1 root root 1350 2月 4 15:04 /etc/docker/certs.d/myregistry.domain.com/ca.crt
[root@docker-app ~]# docker login myregistry.domain.com
Username: admin
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
[root@docker-app ~]# docker push myregistry.domain.com/redis
The push refers to repository [myregistry.domain.com/redis]
0233556febff: Pushed
d7344f36256c: Pushed
9f839e56c434: Pushed
35e1c7a16066: Pushed
6d35c327901c: Pushed
488dfecc21b1: Pushed
latest: digest: sha256:d8fa379d0db05f5a57c0bb6a85457d2fe4254053e35ece01bc53fbcf679bc10a size: 1572
[root@docker-registry ~]# curl -k https://192.168.195.128:443/v2/_catalog -u admin
Enter host password for user 'admin':
{"repositories":["httpd","mysql","nginx","redis","tomcat"]}
搭建Web Registry
- 下载镜像docker-web-registry
[root@docker-registry ~]# docker search docker-registry-web
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
hyper/docker-registry-web Web UI, authentication service and event rec… 182 [OK]
2、重新创建仓库
docker run -d \
--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 /opt/data/registry/:/var/lib/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 \
-e REGISTRY_STORAGE_DELETE_ENABLED=true \ ##删除功能打开
registry
3、运行docker-web-registry容器
docker run -d -p 8080:8080 \
--name registry_web \
--link registry:myregistry.domain.com \
-e REGISTRY_URL=https://myregistry.domain.com/v2/ \ ##仓库资源地址
-e REGISTRY_TRUST_ANY_SSL=true \ ##允许ssl加密认证
-e REGISTRY_BASIC_AUTH="YWRtaW46MTIzNDU2" \ ##认证密码(查看/root/.docker/config.json文件)
-e REGISTRY_NAME=myregistry.domain.com \ ##仓库名字,镜像
-e REGISTRY_READONLY=false \ ##只读属性关闭
hyper/docker-registry-web
web页面查看镜像