VMware 在2020年4月2日发布了vSphere 7.0的正式版。这个版本的vSphere最显著的特性之一是它在hypervisor层内部创建了Kubernetes控制平面。该功能使vSphere大大扩展了它所能运行的工作负载范围,涵盖了更多当前流行的应用程序。我们将此功能之前称为“ Project Pacific”或WCP(工作负载控制平面),现在的正式名称是“vSphere with Kubernetes”。要了解有关vSphere 7的新功能的更多信息,请访问我们的网站:https://www.vmware.com/products/vsphere.html.
1. 背景介绍
vSphere with Kubernetes 自带了一个内嵌的映像注册表(image registry)–Harbor。 大多数映像注册表(image registry)都启用了HTTPS,Harbor也是如此。通常来说在Kubernetes中部署的应用要访问映像注册表(GCR,Docker Hub或Harbor),您需要准备两种凭证:
- 映像注册表的服务器CA证书。运行映像获(image fetch)取的组件,需要在它的KeyStore有足够的信息来验证注册表的服务器证书。对于Docker Hub和GCR,应该都没有问题,因为客户端系统始终安装了公共认可的知名根证书来验证它们所签名的这些证书。但如果要部署带有自签名证书的私有注册表(例如Harbor),则还有更多设置步骤。
- 访问映像注册表的凭证(通常是用户名和密码)。公共存储库在访问(pull操作)映像的时候不需要凭据,在上传或更新(push操作)映像的时候需要。私有注册表(例如Harbor)在将映像拉取或推送(pull和push)时始终需要凭据。
在实际部署中,对大多数映像注册表的使用可能有多种不同的使用方案。有的在Supervior集群中直接使用内置的harbor,有的在Tanzu集群中使用内置的Harbor,还有的则需要使用他们企业内部已经存在的映像注册表服务。本文将通过实战的方式,来一步步展示如何在不同的部署情况下,正确的配置Supervisor和Tanzu集群,才能流畅的访问映像注册表的服务。下面的实战练习需要几个前提条件:
- 配置好Supervisor Kubernetes集群。请参考:Config a Supervisor Cluster
- 创建并配置好Supervisor Kubernetes集群的命名空间。请参考:Configure Supervisor Cluster Namespaces.
- 下载并安装好Kubernetes客户端根据kubectl和vSphere的插件。请参考:Download and Install the Kubernetes CLI Tools for vSphere
- 在命名空间里创建一个或多个Tanzu Kubernetes 集群。请参考:How to Create Tanzu Kubernetes Clusters.
- 如何设置内置的映像注册表。请参考:Enable a private image registry on a Supervisor Cluster。
2. Docker Client访问内嵌的Harbor
在实际安装过程中,如果用户不提供自己的证书,vSphere with Kubernetes会自己生成一个自签名的证书,内嵌的Harbor也使用这个根证书签发的证书。因此,Docker客户端需要将这个证书导入到系统中,才能使用Harbor服务。
- 通过浏览器登录到Harbor界面。选择你要访问的Project或者(Namespace)。
- 转到“Repositories”页,下载注册表证书
- 将这个证书添加到本机的系统里,例如,在MacOS里需要运行下面的命令(最后的参数是刚才保存证书的文件路径):
$ security add-trusted-cert -d -r trustRoot -k ~/Library/Keychains/login.keychain pathtofile/harbor-cert.crt
- 重启Docker服务
- 通过下面的命令来验证Docker客户端和Harbor的集成(下面的例子中10.147.18.2是我的Harbor服务的IP地址):
$ docker login 10.147.18.2 $ docker pull busybox:latest $ docker tag busybox:latest 10.147.18.2/wangyu/busybox:latest $ docker push 10.147.18.2/wangyu/busybox:latest
3. 从Supervisor集群中访问内置的Harbor
要从Supervisor集群中访问内置的Harbor服务,例如,创建带有指向Harbor存储库的URL的Pod,我们无需执行任何操作即可实现此目的。这是因为,一方面,Harbour Registry和Esxi Spherelet(映像获取服务所在的地方)共享相同的根证书,因此它们自然彼此信任。另一方面,在Supervisor群集中创建命名空间时会自动创建默认的映像像拉取秘钥。
因此这一小节的目的不是需要您执行什么步骤,而是一起来看看系统在创建命名空间的时候,都创建了哪些与映像拉取操作相关的资源和秘钥。
- 通过kubectl命令,以数据中心管理员或者Namespace管理员的身份登录Supervisor 集群。然后执行下面的命令来获得相关的secret(格式为NAMESPACE-default-image-pull-secret)
$ kubectl vsphere login --server=10.117.233.1 --vsphere-username [email protected] $ kubectl get secret wangyu-default-image-pull-secret -o json -n wangyu { "apiVersion": "v1", "data": { ".dockerconfigjson": "ewoJCQkJImF.....QkJfQ==" }, "kind": "Secret", "metadata": { "creationTimestamp": "2020-04-11T10:41:40Z", "name": "wangyu-default-image-pull-secret", "namespace": "wangyu", "ownerReferences": [ { "apiVersion": "registryagent.vmware.com/v1alpha1", "blockOwnerDeletion": true, "controller": true, "kind": "Project", "name": "wangyu", "uid": "1b2a528c-45b5-4262-a5cc-d0d6e1744ccf" } ], "resourceVersion": "76067", "selfLink": "/api/v1/namespaces/wangyu/secrets/wangyu-default-image-pull-secret", "uid": "2c7a7fc1-97fa-49ba-b54a-6c5225ffe487" }, "type": "kubernetes.io/dockerconfigjson }
- 在当前的命名空间里,缺省(default)的 Service Account已经和这个secret绑定在一起了,因此,当你从Harbor拉取映像的时候,就算你什么都没有指定,缺省的也会使用了这个secret
$ kubectl describe sa default -n wangyu Name: default Namespace: wangyu Labels: <none> Annotations: <none> Image pull secrets: wangyu-default-image-pull-secret Mountable secrets: default-token-lqfwr Tokens: default-token-lqfwr Events: <none>
- 下面是个在Supervisor集群中使用内置Harbor服务来创建pod的例子:
$ more busybox-harbor.yaml apiVersion: v1 kind: Pod metadata: name: busybox spec: imagePullSecrets: - name: externalimgpull containers: - image: 10.147.18.2/wangyu/wybusybox:latest command: - sleep - "3600" imagePullPolicy: IfNotPresent name: busybox restartPolicy: Always
4. 从Supervisor集群中访问外部自签名的Harbor
如果要使用已有的映像注册表(Harbor或其他),那么要从Supervisor群集访问这个注册表需要更多的配置步骤,尤其是您的注册表服务正在使用自签名证书。
- 通过kubectl命令,以数据中心管理员的身份登录Supervisor 集群。
- 在命名空间里创建一个映像拉取的secret,例如在下面的例子中,我们创建了一个名为“externalimagepull”的secret(你可以任意选择其他的名称)。”–docker-server”指向你的Harbor地址;最后还需要提供登录Harbor的用户名和密码。
$ kubectl -n wangyu create secret docker-registry externalimgpull --docker-server=10.147.18.2 \ --docker-username=YourName --docker-password=YourPasswd secret/externalimgpull created
- 通过浏览器登录到Harbor界面。选择你要访问的Project或者(Namespace)。
- 转到“Repositories”页,下载注册表证书.
- 在系统命名空间(kube-system)里去修改 image-fetcher-ca-bundle这个资源,将刚才下载的证书的内容追加到这个资源的证书列表的后面,并且保存。
$ kubectl edit configmap image-fetcher-ca-bundle -n kube-system .... apiVersion: v1 data: ca-bundle: | -----BEGIN CERTIFICATE----- MIIENTCCAx2gAwIBAgIJAPSI+BwiQ0E/MA0GCSqGSIb3DQEBCwUAMIGlMQswCQYD VQQDDAJDQTEXMBUGCgmSJomT8ixkARkWB3ZzcGhlcmUxFTATBgoJkiaJk/IsZAEZ FgVsb2NhbDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExJzAlBgNV BAoMHnN0bmV0LWNwZC12Yy0xNy5lbmcudm13YXJlLmNvbTEbMBkGA1UECwwSVk13 YXJlIEVuZ2luZWVyaW5nMB4XDTIwMDMwMTEyNTE0MVoXDTMwMDIyNzEyNTE0MVow gaUxCzAJBgNVBAMMAkNBMRcwFQYKCZImiZPyLGQBGRYHdnNwaGVyZTEVMBMGCgmS JomT8ixkARkWBWxvY2FsMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5p YTEnMCUGA1UECgwec3RuZXQtY3BkLXZjLTE3LmVuZy52bXdhcmUuY29tMRswGQYD VQQLDBJWTXdhcmUgRW5naW5lZXJpbmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQCxkC3pJGQWYQP55bN9Brb3qwDl7aoEX1r/g21/jFoX35nwh7WC/5Jf waQ1S0DiVytIdeZNoy/3W4/bKz0tDLTb+cmm2irJtn+5potx4ntZvrFJkTbSrJpO 7yrZXefbCYFnMCW9mzwAx/G97Es+s5+fdnv6epTy18fNC+AogAlt210SGvlM0wbw k+oEZZBdVjz7/Meszw+V7EzG4KS5o5giMYBHAABkHDHlnAAh/5/93MdK9+j/Mg2n izlQNXO+2VVG8LoVm1MLp+RiV5r410TmjER1W4TYRgtI390otZLLHSfI6xYQYey0 W7jjatXwneg/M1x10Do6fW1xxlYYg+l5AgMBAAGjZjBkMB0GA1UdDgQWBBRbVNOq DOikfAxH0lWdp0hgBIG1+jAfBgNVHREEGDAWgQ5lbWFpbEBhY21lLmNvbYcEfwAA ATAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADANBgkqhkiG9w0B AQsFAAOCAQEAKptfB8HHyXpe2t2ncLUgC13WYk9LIJZeMlKtZiCTYIP6fsavNO43 JD5TUw7tc6dbKB9EQNDghuvekmzUazkaxksD3fMVERdeNqqGPGGmApIZJ71BAHBV XS+ayql9Hxr/vvhwVIwPWkBsBfd3bStsNeNcBLeQyYRDpLs8pI6JAqpzDj2A2dIO 2YvUDsK4/bY992S3rIKs8mi8oC93O1MewpDTLnJNEbaG95+68sTn+21Xq88blDTP V2YdsN2f67njV7wqbRPN+W/fGSv6UD6wLdb+EB2Rxjx7WHDCmBXyCFIkKFEj9EQw 7u2eCZG38ZbubwKJLITFHV2N9nZf/Kx3Lw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIENTCCAx2gAwIBAgIJAPSI+BwiQ0E/MA0GCSqGSIb3DQEBCwUAMIGlMQswCQYD VQQDDAJDQTEXMBUGCgmSJomT8ixkARkWB3ZzcGhlcmUxFTATBgoJkiaJk/IsZAEZ FgVsb2NhbDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExJzAlBgNV BAoMHnN0bmV0LWNwZC12Yy0xNy5lbmcudm13YXJlLmNvbTEbMBkGA1UECwwSVk13 YXJlIEVuZ2luZWVyaW5nMB4XDTIwMDMwMTEyNTE0MVoXDTMwMDIyNzEyNTE0MVow gaUxCzAJBgNVBAMMAkNBMRcwFQYKCZImiZPyLGQBGRYHdnNwaGVyZTEVMBMGCgmS JomT8ixkARkWBWxvY2FsMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5p YTEnMCUGA1UECgwec3RuZXQtY3BkLXZjLTE3LmVuZy52bXdhcmUuY29tMRswGQYD VQQLDBJWTXdhcmUgRW5naW5lZXJpbmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQCxkC3pJGQWYQP55bN9Brb3qwDl7aoEX1r/g21/jFoX35nwh7WC/5Jf waQ1S0DiVytIdeZNoy/3W4/bKz0tDLTb+cmm2irJtn+5potx4ntZvrFJkTbSrJpO 7yrZXefbCYFnMCW9mzwAx/G97Es+s5+fdnv6epTy18fNC+AogAlt210SGvlM0wbw .... configmap/image-fetcher-ca-bundle edited
- 现在可以在Supervisor集群上部署Pod或Deployment,将刚才创建的secret应用到部署文件中去:
$ more nginx-harbor.yaml apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: myapp spec: replicas: 1 selector: matchLabels: app: myapp template: metadata: labels: app: myapp spec: containers: - name: nginx image: 10.147.18.2/wangyu/nginx:latest ports: - containerPort: 80 imagePullSecrets: - name: externalimgpull
- 当然,你可以将命名空间里缺省(default)的Service Account和这个映像拉取的secret进行绑定,这样,在当前命名空间部署Pod或Deployment的时候,就不需要每次在部署文件中指定映像拉取的secret:
$ kubectl get sa default -o json -n wangyu { "apiVersion": "v1", "imagePullSecrets": [ { "name": "wangyu-default-image-pull-secret" } ], "kind": "ServiceAccount", "metadata": { "creationTimestamp": "2020-03-06T07:19:28Z", "name": "default", "namespace": "wangyu", "resourceVersion": "850464", "selfLink": "/api/v1/namespaces/wangyu/serviceaccounts/default", "uid": "96b9abe5-14aa-4d55-bf66-02ce4bffc5ec" }, "secrets": [ { "name": "default-token-kfwj8" } ] } $ kubectl edit sa default
5. 从Tanzu集群中访问自签名的Harbor
当您想从Tanzu Kubernetes群集访问私有映像存储库时,内置的Harbor 注册表和外部其他注册表之间没有什么区别。因为Tanzu Kubernetes群集既没有映像拉取秘钥的默认设置,它们也根本不信任您的私有注册表(例如Harbor)的自签名证书。所以要想从Tanzu Kubernetes集群访问自签名的注册表(内置或外部),需要更多的步骤来设置证书和凭证。证书的设置相对来说要更加麻烦一些,它需要在Tanzu Kubernetes群集的每一个节点上(包括所有的Master节点和Workder节点),都要加入Harbor自签名的CA的证书信息,使其信任。下面我们来看看具体的步骤:
- 通过浏览器登录到Harbor界面。选择你要访问的Project或者(Namespace)。
- 转到“Repositories”页,下载注册表证书并保存到一个文件里,例如crt.
- 通过kubectl命令,以数据中心管理员或者Namespace管理员的身份登录Supervisor 集群
$ kubectl vsphere login --server=10.117.233.1 --vsphere-username [email protected]
- 在Tanzu集群所在的Supervisor命名空间里查看秘钥的信息,可以通过以下命令获得有关Tanzu集群跟SSH登录相关的秘钥信息,记住这个secret的名字,在下面的例子输出中是“my-tanzu-cluster-ssh”。
kubectl get secret -n wangyu | grep ssh-auth my-tanzu-cluster-ssh kubernetes.io/ssh-auth 1 18d
- 查看Tanzu集群的节点信息和IP地址
$ kubectl get virtualmachines -n wangyu NAME AGE my-tanzu-cluster-control-plane-kffsj 18d wy-tanzu-cluster-workers-c5jwz-86b575c4bb-5lbst 18d wy-tanzu-cluster-workers-c5jwz-86b575c4bb-9hwqg 18d wy-tanzu-cluster-workers-c5jwz-86b575c4bb-lvth9 18d $ kubectl get virtualmachines -n wangyu -o yaml | grep vmIp vmIp: 10.244.1.2 vmIp: 10.244.1.3 vmIp: 10.244.1.5 vmIp: 10.244.1.4
- 创建configmap,以便于将Harbor的证书导入。
$ kubectl create configmap harborca --from-file=harbor.crt -n wangyu
- 通过kubectl创建一个跳板机,并且将访问Tanzu集群节点的秘钥和Harbor的证书也一起放在跳板机里,就可以方便的将这个证书信息导入到Tanzu集群中的各个节点里。
$ more jumpbox.yaml apiVersion: v1 kind: Pod metadata: name: jumpbox spec: containers: - image: "photon:3.0" name: jumpbox command: [ "/bin/bash", "-c", "--" ] args: [ "yum install -y openssh-server; mkdir /root/.ssh; cp /root/ssh/ssh-privatekey /root/.ssh/id_rsa; \ chmod 600 /root/.ssh/id_rsa; while true; do sleep 30; done;" ] volumeMounts: - mountPath: "/root/ssh" name: ssh-key readOnly: true - name: harborca mountPath: /tmp/harborca volumes: - name: ssh-key secret: secretName: my-tanzu-cluster-ssh - name: harborca configMap: name: harborca
- 在当前的命名空间里部署这个跳板机
$ kubectl apply -f jumpbox.yaml -n wangyu pod/jumpbox created
- 并且在每个节点上执行下面的命令(注意替换节点的IP地址)。
$ kubectl exec -it jumpbox /usr/bin/scp /tmp/harborca/harbor.crt [email protected]:/tmp/harbor.crt $ kubectl exec -it jumpbox /usr/bin/ssh [email protected] 'sudo bash -c \ "cat /tmp/harbor.crt >> /etc/pki/tls/certs/ca-bundle.crt"' $ kubectl exec -it jumpbox /usr/bin/ssh [email protected] 'sudo systemctl restart docker.service'
- 以Tanzu集群管理员的身份登录。(详细步骤请参考vSphere with Kubernetes实战之:用户访问控制)
- 在Tanzu的命名空间里(你想要部署应用的命名空间)创建一个映像拉取的secret,例如在下面的例子中,我们在default命名空间里创建了一个名为“externalimagepull”的secret(你可以任意选择其他的名称)。”–docker-server”指向你的Harbor地址;最后还需要提供登录Harbor的用户名和密码。
$ kubectl -n default create secret docker-registry externalimgpull --docker-server=10.147.18.2 \ --docker-username=YourName --docker-password=YourPasswd secret/externalimgpull created
- 现在可以在Tanzu集群上的命名空间(本例中为default)部署Pod或Deployment,将刚才创建的secret应用到部署文件中去:
$ more nginx-harbor.yaml apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: myapp spec: replicas: 1 selector: matchLabels: app: myapp template: metadata: labels: app: myapp spec: containers: - name: nginx image: 10.147.18.2/wangyu/nginx:latest ports: - containerPort: 80 imagePullSecrets: - name: externalimgpull
- 设置完成后可以删除跳板机。
6. 总结
在各种开发部署的环境下,一般的映像注册表都会使用自签名的证书。如果是在Supervisor集群中使用vSphere with Kubernetes内置的harbor,那比较简单,基本上不需要做任何额外的配置。但是如果想在Tanzu集群中也使用内置或者外置的映像注册表,就需要按照本文描述的一步步操作来完成这些任务。
JiaMing的评论:
文中第五大步第7小步需要ingress和egress连接公网
在一些客户环境,在做vsphere with kubernetes测试时,ingress个egress不能连接公网,这样用于ssh到tanzu集群节点的jumpbox无法从公网拉取photon镜像。此时,我们需要从公网拉取photon镜像并装上ssh工具,把镜像打包上传至harbor,让jumpbox拉取harbor中的photon镜像作为ssh到tanzu集群节点的跳板机。
1.从公网拉取photon镜像
docker pull photon:3.0
2.利用该镜像创建一个容器,并给容器安装ssh
docker run -t -i photon:3.0 /bin/bash
yum install openssh-server
exit
3.查找刚修改的容器名
docker ps -a
例子中container id 为26ef51868114
4.将修改过的容器作为镜像上传
docker commit 26ef51868114 photon-ssh
5.把镜像上传到harbor
docker login
docker tag photon-ssh // photon-ssh
docker push // photon-ssh
6.在superviser cluster从harbor拉取photon-ssh镜像创建跳板机,在yaml里把image指向harbor的镜像。
apiVersion: v1 kind: Pod metadata: name: jumpbox spec: containers: - image: // photon-ssh name: jumpbox command: [ "/bin/bash", "-c", "--" ] args: [ "rm -rf /root/.ssh; mkdir /root/.ssh; cp /root/ssh/ssh-privatekey /root/.ssh/id_rsa;chmod 600 /root/.ssh/id_rsa; while true; do sleep 30; done;" ] volumeMounts: - mountPath: "/root/ssh" name: ssh-key readOnly: true - name: harborca mountPath: /tmp/harborca volumes: - name: ssh-key secret: secretName: my-tanzu-cluster-ssh - name: harborca configMap: name: harborca
后续步骤一致