Docker 私有仓库

在前面的章节中,我们使用了Kubernetes和容器技术实现了微服务的发现、负载均衡、持续部署等需求。然而,我们并未提到Docker镜像的配置。默认的,我们使用了Docker官方默认的Docker镜像。然而在实际工作中,我们最好使用Docker私有仓库。

想象一下,持续部署流程中,我们会将微服务的jar包自动构建,并打成Docker镜像,推送到Docker镜像服务器,然后部署到Kubernetes集群上。

想象下,如果我们使用默认的公共镜像,等于将自己的产品完全"开源"地暴露给了互联网。这里"开源"打了引号,虽然打成jar包后都是class文件,但是可以通过反编译工具轻松的解析到源代码,和开源是差不多的。

因此,与之前的私有maven仓库类似,我们也需要一个私有的Docker仓库。

启动私有仓库的Kubernetes服务

有意思的是,Docker私有仓库(Docker registry)本身也是一个Docker镜像。有没有鸡生蛋,蛋生鸡的感觉:-)

与之前所有的服务类似,我们也将Docker私有仓库部署在Kubernetes上。首先,还是先创建物理机上的挂载点:

sudo mkdir /data/registry/
sudo chmod -R 777 /data/registry/

然后创建部署, lmsia-docker-registry.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: lmsia-docker-registry-deployment
spec:
  selector:
    matchLabels:
      app: lmsia-docker-registry
  replicas: 1
  template:
    metadata:
      labels:
        app: lmsia-docker-registry
    spec:
      restartPolicy: Always
      nodeSelector:
        kubernetes.io/hostname: minikube
      containers:
      - name: lmsia-docker-registry-ct
        image: registry:2.6.2
        ports:
        - containerPort: 5000
          hostPort: 5000
        volumeMounts:
        - mountPath: "/auth"
          name: volume
          subPath: auth
        - mountPath: "/var/lib/registry"
          name: volume
          subPath: registry
        env:
        - name: "REGISTRY_STORAGE_DELETE_ENABLED"
          value: "true"
      volumes:
      - name: volume
        hostPath:
          path: /data/registry/

在上面的描述文件中,进行了如下配置:

  • 创建了registry容器2.6.2版本,暴露端口5000
  • 强制绑定到物理机"minikube"上,挂掉自动重启
  • 支持删除镜像

应用一下,成功:

kubectl apply -f ./lmsia-docker-registry.yaml

向私有仓库发布镜像

在本书架构的应用场景下,私有仓库的使用场景是:

  • jenkins完成自动构建,并向私有仓库发布镜像
  • 其他Kubernetes节点,从私有仓库拉取镜像,启动Pod

我们这里先完成第一步,我们登录minikube来模拟发布镜像:

首先登录私有仓库

minikube ssh
$docker login localhost:5000
test
pass

需要说明的是,我们创建的私有仓库,默认有一个用户test/pass,如果你认为安全性不够的话,可以参考官方文档自行修改,这里不再赘述。

还需要登录共有仓库

$docker login
coder4
xxxxxx

注意:这里共有仓库的登录步骤不可少,因为我们接下来需要在本地读取共有仓库的镜像。

然后我们编辑一个镜像Dockerfile:

FROM alpine
CMD sleep 3600

编译并发布到私有仓库上

$docker build -t alpine_test .
$docker tag alpine_test $DR_DOMAIN/alpine_test:test_1.0
$docker push $DR_DOMAIN/alpine_test

至此,我们已经发布到了私有仓库上,查询后,发现成功了:

$ curl http://localhost:5000/v2/_catalog
{"repositories":["alpine_test"]}

Kubernetes从私有仓库拉取镜像

对于Kubernetes集群而言,我们不太可能登录到每台机器上手工执行docker login。

幸运的是,Kubernetes为我们提供了解决方案。

创建一个regcred,相当于一个在集群内部通用的凭证:

kubectl create secret docker-registry regcred --docker-server=192.168.99.100:5000 --docker-username=user --docker-password=pass --docker-email=lihy@coder4.com
secret "regcred" created

查看一下:

kubectl get secret regcred --output="jsonpath={.data.\.dockerconfigjson}" | base64 -d
{"auths":{"192.168.99.100:5000":{"username":"user","password":"pass","email":"lihy@coder4.com","auth":"dXNlcjpwYXNz"}}}

下面,我们来创建一个使用这个私有仓库的Pod,看一下YAML

apiVersion: v1
kind: Pod
metadata:
  name: lmsia-private-test
spec:
  containers:
  - name: lmsia-private-test
    image: 192.168.99.100:5000/alpine_test:test_1.0
  imagePullSecrets:
  - name: regcred

如上,特殊的配置有:

  • 我们在image定义之前,增加了私服的前缀
  • 最后增加了刚才配置好的imagePullSecrets

apply之后,可以发现启动成功了。

kubectl get pods
NAME                                                READY     STATUS    RESTARTS   AGE
lmsia-docker-registry-deployment-569fd8b594-ldch2   1/1       Running   0          2m
lmsia-private-test                                  1/1       Running   0          57s

提醒一下,如果启动失败,并且错误原因是:

  Warning  Failed                 4s (x2 over 20s)  kubelet, minikube  Failed to pull image "192.168.99.100:5000/alpine_test": rpc error: code = Unknown desc = Error response from daemon: Get https://192.168.99.100:5000/v2/: http: server gave HTTP response to HTTPS client

那么,请参考这篇文章进行解决insecure repository in minikube

至此,我们完成了Docker私有仓库的搭建和访问。

思考与拓展

  • 在Docker Registry 2后,默认强制采用加密认证方式,请结合这篇文章,将私有仓库的部署改为加密方式。
下一节:minikube是入门Kubernetes的优秀工具。使用minikube,可以轻松地在本地运行Kuberntes的主要功能。