迈入Docker、Kubernetes容器世界的大门

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 本文通过简单的示例,带领初学者快速迈入Docker、Kubernetes(K8S)容器世界的大门。假设,你已拥有一个K8S集群,否则,可通过minikube或minishift快速搭建一实验环境。 Docker Docker与K8S ​ Docker本质上是一种虚拟化技术,类似于KVM、XEN、VMWARE,但其更轻量化,且将Docker部署在Linux环境时,其依赖于Linux容器技术(LXC)。

本文通过简单的示例,带领初学者快速迈入DockerKubernetes(K8S)容器世界 的大门。假设,你已拥有一个K8S集群,否则,可通过minikubeminishift快速搭建一实验环境。

Docker

DockerK8S

Docker本质上是一种虚拟化技术,类似于KVMXENVMWARE,但其更轻量化,且将Docker部署在Linux环境时,其依赖于Linux容器技术(LXC)。Docker较传统KVM等虚拟化技术的一个区别是无内核,即多个Docker虚拟机共享宿主机内核,简而言之,可把Docker看作是无内核的虚拟机,每Docker虚拟机有自己的软件环境,相互独立。

K8SDocker之间的关系,如同Openstack之于KVMVSphere之于VMWAREK8S是容器集群管理系统,底层容器虚拟化可使用Docker技术,应用人员无需与底层Docker节点直接打交道,通过K8S统筹管理即可。

Docker基础

​ 如下所示,运行docker run -it --name test-docker busybox /bin/sh命令,观察其输出,可发现docker先在本地查找名为busybox镜像(Image)1,若本地无镜像,则从docker.io官方镜像库(Registry)下载镜像后保存到本地,接着以此镜像构建一个名为test-docker虚拟机,其Docker官方术语命名为容器(Container)

# docker run -it --name test-docker busybox /bin/sh
Unable to find image 'busybox:latest' locally
Trying to pull repository docker.io/library/busybox ... 
latest: Pulling from docker.io/library/busybox
f70adabe43c0: Pull complete 
Digest: sha256:186694df7e479d2b8bf075d9e1b1d7a884c6de60470006d572350573bfa6dcd2
/ # 

Docker较传统KVMVMware虚拟机更轻量,如下所示,test-docker容器不会运行额外的系统与内核进程,其仅运行docker run命令提供的/bin/sh进程:

/ # ps -ef
PID USER TIME COMMAND
 1 root 0:00 /bin/sh
 7 root 0:00 ps -ef

​ 如在Openstack中创建虚拟机,首先需在Glance镜像库中存储虚拟机镜像,而后才能选择镜像以创建虚拟机。Docker同理,且官方提供一共享的镜像仓库(Registry),其中存储了各式各样的镜像(Image)。如本例用busybox镜像创建容器,其镜像被拉(pull)到了本地,可执行如下命令检查发现其仅1MB左右,相当轻量。

# docker images|grep busybox
docker.io/busybox latest 8ac48589692a 5 weeks ago 1.146 MB

​ 通过本节,我们了解了3个Docker基本要素:镜像仓库(Registry)中存储了镜像(Image),而镜像(Image)包含了程序运行所需的软件环境,当部署容器(Container)时,镜像(Image)通过网络被拉取到Doker主机(Node)

Kubernetes

K8SGoogle开源容器集群管理系统,其源于Google内部管理系统Borg,以下将通过一个个简单连贯的示例,带领初学者熟悉K8S集群。

Pod

K8SPod为最小单位来调度并管理Docker容器(Container),其中1个Pod可含多个容器,且相同Pod里的容器共享本地网络,容器间可通过localhost地址互访,即容器如同部署在相同的主机上,而以Pod为最小单元来调度则表明:Pod内的容器被调度到相同的Docker节点上。

​ 如下所示,创建一名为myhttpPod,其包含一个使用httpd镜像部署的容器,容器名为myhttp

# cat > /tmp/myhttpd.pod <<EOF
apiVersion: v1
kind: Pod
metadata:
 name: myhttp
 labels:
 app: myhttp
spec:
 containers:
 - name: myhttp
 image: httpd
EOF
% kubectl create -f /tmp/myhttpd.pod 

​ 执行kubectl get pod命令观察Pod运行成功后,接着验证容器能提供web服务:

# kubectl get pod
NAME READY STATUS RESTARTS AGE
myhttp 1/1 Running 0 1h
# kubectl describe pod myhttp|grep IP
IP: 10.129.0.232
# curl 10.129.0.232
<html><body><h1>It works!</h1></body></html>

Deployment

​ 将应用直接以Pod形式部署很少见,主因是:Pod无法提供弹性伸缩,且节点故障时K8S无法将其调度到幸存节点上,缺少自愈能力。鉴于此,应用常使用“镜像(Rc)/部署(Deployment)”部署,且在K8S新版本中,官方推荐用Deployment替代Rc部署无状态(Stateless)应用。

​ 执行kubectl delete pod myhttp删除pod后,换成以Deployment部署:

# cat > myhttp.yaml <<EOF 
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
 labels:
 app: myhttp
 name: myhttp
spec:
 replicas: 1
 selector:
 matchLabels:
 app: myhttp
 template:
 metadata:
 labels:
 app: myhttp
 spec:
 containers:
 - image: httpd
 name: myhttp
EOF
# kubectl create -f /tmp/myhttp.yaml

Deployment中的.spec.replicas表明部署多少个Pod,如本例当前仅含一Pod

# kubectl get deploy,pod
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deploy/myhttp 1 1 1 1 2m

NAME READY STATUS RESTARTS AGE
po/myhttp-7bc6d8b87c-gzlkq 1/1 Running 0 2m

​ 执行kubectl delete pod <pod_name>删除Pod后,可发现deployment将自动重建pod,其将确保拥有.spec.replicaspod数量,即意味着,当pod异常时,deployment具备自愈特性。

# kubectl delete pod myhttp-7bc6d8b87c-gzlkq # kubectl get pod -w
NAME READY STATUS RESTARTS AGE
myhttp-7bc6d8b87c-dhmtz 0/1 ContainerCreating 0 2s
myhttp-7bc6d8b87c-dhmtz 1/1 Running 0 8s
myhttp-7bc6d8b87c-gzlkq 1/1 Terminating 0 8m

​ 当需伸缩或扩展应用时,若以Pod形式部署,则需删除或创建Pod,而若使用Deployment部署,则我们仅需调整.spec.replicas,而后K8S镜像控制器将自动调整Pod数量。如下所示,扩展http应用为2服务:

# kubectl scale deploy/myhttp --replicas=2 # kubectl get pod -w
NAME READY STATUS RESTARTS AGE
myhttp-7bc6d8b87c-cj4g8 0/1 ContainerCreating 0 3s
myhttp-7bc6d8b87c-zsbcc 1/1 Running 0 8m
myhttp-7bc6d8b87c-cj4g8 1/1 Running 0 18s

# kubectl get deploy
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
myhttp 2 2 2 2 21m

​ 执行kubectl delete pod <pod_name>删除Pod后,可发现Pod名(即容器主机名)及IP是随机分配的,那么,我们该如何访问应用?

# kubectl get pod # kubectl describe pod myhttp-7bc6d8b87c-cj4g8|grep IP
IP: 10.129.3.28

Service

Service服务类似于传统的F5A10等硬件负载均衡,但其在K8S中通过软件实现,且当伸缩应用时可实时跟踪后端Server,无需人为调整。

内部访问


我们将对上节部署的myhttp应用创建一个Service服务,但在此前,先创建一个Pod作为集群内部客户端以用于后续Service验证。因下面验证Svc将使用curl工具,而官方centos镜像包含此工具,故用此镜像创建Pod,且为保证Pod一直运行不退出,使用了command在前台执行了无限循环命令。

# kubectl create -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
 name: myclient
 labels:
 app: myclient
spec:
 containers:
 - name: myclient
 image: centos
 command: ['sh','-c','while true; do sleep 3600; done;']
EOF

​ 执行如下命令为myhttp应用创建一个myhttp-int的服务:

# kubectl expose deployment myhttp --port=8080 --target-port=80 --name=myhttp-int
service "myhttp-int" exposed

​ 上面命令等价于使用下面的Yaml文件手动创建Service:创建名为myhttp-int的服务,其8080端口指向后端服务的80端口,而后端服务是通过selector选择label(标签)app:myhttpPod,观察myhttp Deployment,可发现.spec.template.metadata.labels定义的标签就是app:myhttp,故而,通过myhttp-int:8080即可访问myhttp服务。

apiVersion: v1 kind: Service metadata: labels: app: myhttp name: myhttp-int spec: clusterIP: ports: - port: 8080 protocol: TCP targetPort: 80 selector: app: myhttp sessionAffinity: None

​ 在测试容器中通过myhttp-int:8080访问Service,可发现将负载均衡到后端的两pod上:

# kubectl get pod
NAME READY STATUS RESTARTS AGE
myclient 1/1 Running 0 1h
myhttp-7bc6d8b87c-cj4g8 1/1 Running 0 1d
myhttp-7bc6d8b87c-zsbcc 1/1 Running 0 1d

# 重置web主页,输出每Pod名称以便后续观察 # kubectl exec myhttp-7bc6d8b87c-cj4g8 -it -- sh -c "hostname>htdocs/index.html" # kubectl exec myhttp-7bc6d8b87c-zsbcc -it -- sh -c "hostname>htdocs/index.html" # kubectl exec -it myclient -- curl myhttp-int:8080
myhttp-7bc6d8b87c-cj4g8
# kubectl exec -it myclient -- curl myhttp-int:8080
myhttp-7bc6d8b87c-zsbcc

​ 当伸缩Pod时,我们可通过如下命令观察到Service将动态跟踪后端(Endpoints)服务:

# kubectl get endpoints myhttp-int
NAME ENDPOINTS AGE
myhttp-int 10.129.0.237:80,10.129.3.28:80 1h

# kubectl scale deploy myhttp --replicas=3 # kubectl get endpoints myhttp-int
NAME ENDPOINTS AGE
myhttp-int 10.129.0.237:80,10.129.3.28:80,10.131.0.194:80 1h

外部访问


​ 若应用需向K8S集群外提供服务,则可创建类型为NodePortService,此时K8S集群上所有节点均监听nodePort指定的端口,故外部应用可通过集群中任一节点访问集群内部提供的服务。

# kubectl create -f - <<EOF 
apiVersion: v1
kind: Service
metadata:
 labels:
 app: myhttp
 name: myhttp-pub
spec:
 type: NodePort
 ports:
 - port: 8080
 nodePort: 30001
 protocol: TCP
 targetPort: 80
 selector:
 app: myhttp
 sessionAffinity: None
EOF 

​ 执行如下命令检查服务,发现一个为ClusterIP类型,一个为NodePort类型,但两者均分配了ClusterIP地址:

# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
myhttp-int ClusterIP 172.30.37.43 <none> 8080/TCP 1h
myhttp-pub NodePort 172.30.6.69 <none> 8080:30001/TCP 3m

myhttp-pub服务通过nodePort打开了集群各节点的主机端口,此时可通过集群任何节点访问服务:

# curl 192.168.220.21:30001
myhttp-7bc6d8b87c-zsbcc
# curl 192.168.230.21:30001
myhttp-7bc6d8b87c-zsbcc
# curl 192.168.240.21:30001
myhttp-7bc6d8b87c-cj4g8

​ 通过NodePort类型的Service虽可将服务暴露到集群外部,但问题是:端口数量有限(限制为30000-32767)、节点故障后,通过此节点访问服务将失败。鉴于此原因,NodePort类型的Service不常用,而是换成使用Ingress的技术来暴露服务到集群外部,但为简单考虑,本文不再讲解Ingress

Configmap

​ 当容器异常时,镜像控制器用Image重建Container,此时对容器的修改会丢失,故而,若需自定义httpd镜像的httpd.conf文件,我们不应直接登录各容器修改配置,而应考虑使用K8S提供的Configmap2技术,其作为中央存储配置库所创建的文件将Pod共享。

​ 如下所示,为简单考虑,我们随意创建一文件并挂载到Deployment中,修改Configmap,扩展Deployment,用此来讲解Configmap作用。

创建一名为my-configcm3


# kubectl create -f - <<EOF
apiVersion: v1
metadata:
 name: my-config
data:
 hosts: |
 127.0.0.1 localhost localhost.localdomain
 #::1 localhost localhost.localdomain
kind: ConfigMap
EOF

执行kubectl edit deploy myhttp修改Deployment,将cm挂载到/etc/myhosts目录中。完整Yaml文件如下(PS:添加volumeMountsvolume):


apiVersion: extensions/v1beta1 kind: Deployment metadata: labels: app: myhttp name: myhttp spec: replicas: 1 selector: matchLabels: app: myhttp template: metadata: labels: app: myhttp spec: containers: - image: httpd name: myhttp volumeMounts: - name: config-hosts mountPath: /etc/myhosts volumes: - name: config-hosts configMap: name: my-config

​ 修改Deploy后,可发现Pod将自动重建,而后检查每Pod可发现目录中含有cmhosts文件:

# kubectl get pod
NAME READY STATUS RESTARTS AGE
myhttp-774ffbb989-gz6bd 1/1 Running 0 11m
myhttp-774ffbb989-k8m4b 1/1 Running 0 11m
myhttp-774ffbb989-t74nk 1/1 Running 0 11m

# kubectl exec -it myhttp-774ffbb989-gz6bd -- ls /etc/myhosts
hosts
# kubectl exec -it myhttp-774ffbb989-gz6bd -- cat /etc/myhosts/hosts
127.0.0.1 localhost localhost.localdomain
#::1 localhost localhost.localdomain

修改cm,几分钟后,可发现pod中的配置被自动更新:


# kubectl edit cm my-config
...
data:
 hosts: |
 127.0.0.1 localhost localhost.localdomain
 ::1 localhost localhost.localdomain
...

# kubectl exec -it myhttp-774ffbb989-gz6bd -- cat /etc/myhosts/hosts
127.0.0.1 localhost localhost.localdomain
::1 localhost localhost.localdomain

扩展应用,继而检查新的Pod,发现其包含cm内容:


# kubectl scale deploy myhttp --replicas=4 # kubectl get pod
myhttp-774ffbb989-gz6bd 1/1 Running 0 15h
myhttp-774ffbb989-k8m4b 1/1 Running 0 15h
myhttp-774ffbb989-t74nk 1/1 Running 0 15h
myhttp-774ffbb989-z5d6h 1/1 Running 0 21s

# kubectl exec -it myhttp-774ffbb989-z5d6h -- cat /etc/myhosts/hosts
127.0.0.1 localhost localhost.localdomain
::1 localhost localhost.localdomain

Secret

​ 相较于Configmap用于保存明文,那么Secret则保存密文,如用户密码等铭感数据,可使用Secret加密保存。如下所示,我们创建一个Secret加密用户与密码,而后提供给容器使用。

OpaqueSecret数据是一个map类型,要求valuebase64编码格式。加密用户与密码:


# echo -n root | base64
cm9vdA==
# echo -n Changeme | base64
Q2hhbmdlbWU=

创建名为userpwd-secretSecret,其包含用户与密码:


# kubectl create -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
 name: userpwd-secret
type: Opaque
data:
 username: cm9vdA==
 password: Q2hhbmdlbWU=
EOF

更新deployment,将secretvolume方式挂载到容器中:


# kubectl edit deployment myhttp
...
spec:
...
 spec:
 containers:
 - image: httpd
 ...
 volumeMounts:
 - name: userpwd
 mountPath: /etc/mysecret
 ...
 volumes:
 - name: userpwd
 secret:
 secretName: userpwd-secret
...

登录容器可发现secret中的key被保存为文件,其内容为value,但在容器内已被正确解密:


# kubectl exec -it myhttp-64575c77c-kqdj9 -- ls -l /etc/mysecret
lrwxrwxrwx. 1 root root 15 May 17 07:01 password -> ..data/password
lrwxrwxrwx. 1 root root 15 May 17 07:01 username -> ..data/username

# kubectl exec -it myhttp-64575c77c-kqdj9 -- cat /etc/mysecret/username
root

Storage

​ 我们将web应用保存到外部存储中,而后挂载到Pod上,这样,无论pod是否重建亦或伸缩,我们发布的应用都不会丢失。

配置NFS存储

为简单考虑,本例采用NFS作为共享存储:

nfs服务器安装软件:

# yum install nfs-utils

配置共享目录:

# mkdir -p /exports/httpd # chmod 0777 /exports/* # chown nfsnobody:nfsnobody /exports/* # cat > /etc/exports.d/k8s.exports <<EOF
/exports/httpd *(rw,root_squash)
EOF

配置防火墙,放行nfs端口:

# firewall-cmd --add-port=2049/tcp # firewall-cmd --permanent --add-port=2049/tcp

配置Selinux以允许Docker写数据到nfs

# getsebool -a|grep virt_use_nfs # setsebool -P virt_use_nfs=true

启动nfs服务:

# systemctl restart nfs-config # systemctl restart nfs-server # systemctl enable nfs-server

K8S集群使用存储

K8S集群每节点安装nfs客户端软件,并设置Selinux权限:

# yum install nfs-utils # setsebool -P virt_use_nfs=true

创建一类型为nfs的持久化卷:PersistentVolume(PV),其指向nfs后端存储:

# kubectl create -f - <<EOF
apiVersion: v1
kind: PersistentVolume
metadata:
 name: httpd
spec:
 accessModes:
 - ReadWriteMany
 capacity:
 storage: 1Gi
 nfs:
 path: /exports/httpd
 server: 192.168.240.11
 persistentVolumeReclaimPolicy: Retain
EOF

创建一持久化卷声明PersistentVolumeClaim(PVC)指向上一步创建的PV

# kubectl create -f - <<EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
 name: httpd
spec:
 accessModes:
 - ReadWriteMany
 resources:
 requests:
 storage: 1Gi
 volumeName: httpd
EOF

检查可发现pvc/httpd绑定到pv/httpd

# oc get pv,pvc
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM ... 
pv/httpd 1Gi RWX Retain Bound demo/httpd ...

NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc/httpd Bound httpd 1Gi RWX 53s

重建deployment,添加volumemount挂载点:

# kubectl delete deploy myhttp # kubectl create -f - <<EOF
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
 labels:
 app: myhttp
 name: myhttp
spec:
 replicas: 3
 selector:
 matchLabels:
 app: myhttp
 template:
 metadata:
 labels:
 app: myhttp
 spec:
 containers:
 - image: httpd
 name: myhttp
 imagePullPolicy: IfNotPresent
 volumeMounts:
 - name: config-hosts
 mountPath: /etc/myhosts
 - name: userpwd
 mountPath: /etc/mysecret
 - name: httpd-htdocs
 mountPath: /usr/local/apache2/htdocs
 volumes:
 - name: config-hosts
 configMap:
 name: my-config
 - name: userpwd
 secret:
 secretName: userpwd-secret
 - name: httpd-htdocs
 persistentVolumeClaim:
 claimName: httpd
EOF

Pod生成后,检查发现nfs目录被挂载到容器内:

# kubectl get pod # kubectl exec -it myhttp-8699b7d498-dlzrm -- df -h
Filesystem Size Used Avail Use% Mounted on
...
192.168.240.11:/exports/httpd 37G 17G 21G 44% /usr/local/apache2/htdocs ...
# kubectl exec -it myhttp-8699b7d498-dlzrm -- ls htdocs # 当前目录为空

登录任何一个容器,将web应用发布到htdocs目录:

# kubectl exec -it myhttp-8699b7d498-dlzrm -- /bin/sh # echo "this is a test of pv" > htdocs/index.html # 容器内

而后,我们删除容器亦或扩展容器,均会发现容器中的htdocs包含所发布的应用:

# kubectl delete pod -l app=myhttp # 删除所有myhttp pod # kubectl get pod # 等待pod重建完毕 # kubectl exec -it myhttp-8699b7d498-6q8tv -- cat htdocs/index.html
this is a test of pv

Satefulset

​ 如上面用Deplyment创建的myhttp应用,其是无状态(stateless)的,主机名是随机动态分配的,且所有Pod可共享挂载相同的存储(volume),但如KafakaZookeeper集群,其是有状态的,需要主机名确定为一,且各自挂载存储,鉴于此,K8S提供了Satefulset技术来满足此类应用需求。

​ 如下所示,我们使用nginx镜像创建一个有状态的集群,用此来讲解Statefulset用法。

不同于Deployment,我们必须先创建一个ClusterIP: NoneService服务:

# kubectl create -f - <<EOF
apiVersion: v1
kind: Service
metadata:
 name: web
 labels:
 app: nginx-web
spec:
 ports:
 - port: 80
 name: web
 clusterIP: None
 selector:
 app: nginx-web
EOF

ServiceClusterIP,也即我们无法直接通过此Servcie访问后端服务。

# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
web ClusterIP None <none> 80/TCP 3s

创建名为nginx的有状态服务,镜像数为2,且注意ServiceName配置为上步创建的Svc

# kubectl create -f - <<EOF
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
 name: nginx
spec:
 serviceName: web
 replicas: 2
 template:
 metadata:
 labels:
 app: nginx-web
 spec:
 containers:
 - name: nginx
 image: nginx
 ports:
 - containerPort: 80
 name: web
EOF

观察pod启动,可发现pod名称为nginx-n格式4,此名称是固定唯一的,且可发现pod是顺序启动的,即容器nginx-nnginx-<n-1>后启动。

# kubectl get pod -w
NAME READY STATUS RESTARTS AGE
nginx-0 0/1 ContainerCreating 0 7s
nginx-0 1/1 Running 0 10s
nginx-1 0/1 Pending 0 0s
nginx-1 0/1 Pending 0 0s
nginx-1 0/1 ContainerCreating 0 1s
nginx-1 1/1 Running 0 13s

创建的servicestatefulset用在dns上以跟踪pod名称:

# kubectl run -i --tty --image busybox dns-test --restart=Never --rm /bin/sh # 如下操作均在刚创建的dns-test pod中进行: # nslookup web # 查找web服务,可发现后端有两pod
...

Name: web
Address 1: 10.129.0.248 nginx-0.web.demo.svc.cluster.local
Address 2: 10.131.0.200 nginx-1.web.demo.svc.cluster.local

# nslookup nginx-0.web # 验证pod名称对应的IP地址
...
Name: nginx-0.web.demo.svc.cluster.local
Address 1: 10.129.0.248 nginx-0.web.demo.svc.cluster.local

# nslookup nginx-1.web
...
Name: nginx-1.web.demo.svc.cluster.local
Address 1: 10.131.0.200 nginx-1.web.demo.svc.cluster.local

配置satefulset挂载volume

# kubectl delete statefulset nginx # 为简单起见,删除以上创建的statefulset # kubectl create -f - <<EOF
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
 name: nginx
spec:
 serviceName: web
 replicas: 2
 template:
 metadata:
 labels:
 app: nginx-web
 spec:
 containers:
 - name: nginx
 image: nginx
 ports:
 - containerPort: 80
 name: web
 volumeMounts:
 - name: www
 mountPath: /usr/share/nginx/html
 volumeClaimTemplates:
 - metadata:
 name: www
 spec:
 accessModes: [ "ReadWriteOnce" ]
 storageClassName: glusterfs-raid0
 resources:
 requests:
 storage: 10Mi
EOF

注意:在volumeClaimTemplates.spec中添加的storageClassName,其指定了名为glusterfs-raid0的存储,这样,当pod生成时,k8s会使用动态提供5创建PVC、PV并自动从存储池glusterfs-raid0中动态分配volume。当然,若使用Storage一节中配置的nfs存储,则此处需删除storageClassName,而后手动创建存储、pv、pvc

检查:

# 如下卷是k8s使用动态提供自动从glusterfs创建的: # kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
www-nginx-0 Bound pvc-4a76e4a9... 1Gi RWO glusterfs-raid0 22h
www-nginx-1 Bound pvc-536e8980... 1Gi RWO glusterfs-raid0 22h

# kubectl get statefulset,pod
NAME DESIRED CURRENT AGE
statefulsets/nginx 2 2 22h

NAME READY STATUS RESTARTS AGE
po/nginx-0 1/1 Running 0 22h
po/nginx-1 1/1 Running 0 22h

# 两Pod挂载各自的卷: # kubectl exec -it nginx-0 -- df -h
Filesystem Size Used Avail Use% Mounted on 
192.168.220.21:vol_e6858... 1016M 33M 983M 4% /usr/share/nginx/html

# kubectl exec -it nginx-1 -- df -h
Filesystem Size Used Avail Use% Mounted on 
192.168.220.21:vol_c659cc... 1016M 33M 983M 4% /usr/share/nginx/html

Namespace

​ 细心的读者会在Storage一节中看到demo/httpd,此demo就是作者所使用的Namespace/Project6。如同Openstack云计算平台提供了多租户用途,其每租户可创建自己的Project(项目)K8S同样提供多租户功能,我们可创建不同的Namespace(命名空间),并将以上所示的PodServiceConfigmap等限制在Namespace中。

​ 刚搭建的K8S集群,默认有如下两Namespace

# kubectl get namespace
NAME DISPLAY NAME STATUS
default Active # 默认命名空间
kube-system Active # k8s自身使用的命名空间

​ 我们可执行如下命令创建命名空间:

# kubectl create namespace demo
namespace "demo" created

​ 而后,执行kubectl命令时可附带”-n <namespace>“参数。如下所示,查询Pod

# kubectl get pod -n demo
NAME READY STATUS RESTARTS AGE
nginx-0 1/1 Running 0 23h
nginx-1 1/1 Running 0 23h

​ 最后,对于Openshift平台,我们可执行如下命令登录到Namespace中,这样,我们就无需每次附带“-n <namespace>”了。

# oc project demo # oc get pod
NAME READY STATUS RESTARTS AGE
nginx-0 1/1 Running 0 23h
nginx-1 1/1 Running 0 23h

结束语

​ 通过本文,我们学习了DockerK8S核心知识,我相信读者应完全可以熟练使用K8S平台了。


  1. 镜像格式为:<image_name>:<image_tag>,若不写image_tag,则默认为latest tag
  2. 参考官方文档:Configure a Pod to Use a ConfigMap
  3. 内容为key:value格式,且一个cm可包含多个
  4. statefulset名称的生成规则是固定的:<statefulset-name>-n
  5. 存储必须支持动态提供,如glusterfs存储,要支持动态提供,必须配置heketi
  6. Openshift平台,其Project即为K8SNamespace

相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
云原生实践公开课
课程大纲 开篇:如何学习并实践云原生技术 基础篇: 5 步上手 Kubernetes 进阶篇:生产环境下的 K8s 实践 相关的阿里云产品:容器服务&nbsp;ACK 容器服务&nbsp;Kubernetes&nbsp;版(简称&nbsp;ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情:&nbsp;https://www.aliyun.com/product/kubernetes
相关文章
|
7天前
|
缓存 Kubernetes Docker
容器服务ACK常见问题之容器服务ACK ingress websocket配置失败如何解决
容器服务ACK(阿里云容器服务 Kubernetes 版)是阿里云提供的一种托管式Kubernetes服务,帮助用户轻松使用Kubernetes进行应用部署、管理和扩展。本汇总收集了容器服务ACK使用中的常见问题及答案,包括集群管理、应用部署、服务访问、网络配置、存储使用、安全保障等方面,旨在帮助用户快速解决使用过程中遇到的难题,提升容器管理和运维效率。
|
7天前
|
存储 运维 Kubernetes
容器服务ACK常见问题之容器服务ACK 淘宝源过期了如何解决
容器服务ACK(阿里云容器服务 Kubernetes 版)是阿里云提供的一种托管式Kubernetes服务,帮助用户轻松使用Kubernetes进行应用部署、管理和扩展。本汇总收集了容器服务ACK使用中的常见问题及答案,包括集群管理、应用部署、服务访问、网络配置、存储使用、安全保障等方面,旨在帮助用户快速解决使用过程中遇到的难题,提升容器管理和运维效率。
|
8天前
|
运维 Kubernetes 监控
构建高效自动化运维体系:基于Docker和Kubernetes的实践指南
【2月更文挑战第30天】 在当今快速发展的云计算时代,传统的IT运维模式已难以满足业务的敏捷性和稳定性需求。本文深入探讨了如何通过Docker容器化技术和Kubernetes集群管理工具构建一个高效、可靠的自动化运维体系。文章首先概述了容器化技术和微服务架构的基本概念,随后详细阐述了基于Docker的应用打包、部署流程,以及Kubernetes在自动化部署、扩展和管理容器化应用中的关键作用。最后,文中通过案例分析,展示了如何在实际场景中利用这些技术优化运维流程,提高系统的整体效率和可靠性。
|
4天前
|
监控 数据可视化 虚拟化
Docker容器常用命令笔记分享
Docker容器常用命令笔记分享
33 2
|
7天前
|
存储 Kubernetes 监控
容器服务ACK常见问题之容器服务ACK启动时readiness告警如何解决
容器服务ACK(阿里云容器服务 Kubernetes 版)是阿里云提供的一种托管式Kubernetes服务,帮助用户轻松使用Kubernetes进行应用部署、管理和扩展。本汇总收集了容器服务ACK使用中的常见问题及答案,包括集群管理、应用部署、服务访问、网络配置、存储使用、安全保障等方面,旨在帮助用户快速解决使用过程中遇到的难题,提升容器管理和运维效率。
|
7天前
|
存储 监控 Kubernetes
容器服务ACK常见问题之cmonitor-agent容器一直没起来如何解决
容器服务ACK(阿里云容器服务 Kubernetes 版)是阿里云提供的一种托管式Kubernetes服务,帮助用户轻松使用Kubernetes进行应用部署、管理和扩展。本汇总收集了容器服务ACK使用中的常见问题及答案,包括集群管理、应用部署、服务访问、网络配置、存储使用、安全保障等方面,旨在帮助用户快速解决使用过程中遇到的难题,提升容器管理和运维效率。
|
7天前
|
存储 Kubernetes 监控
容器服务ACK常见问题之容器服务ACK worker节点选择不同地域失败如何解决
容器服务ACK(阿里云容器服务 Kubernetes 版)是阿里云提供的一种托管式Kubernetes服务,帮助用户轻松使用Kubernetes进行应用部署、管理和扩展。本汇总收集了容器服务ACK使用中的常见问题及答案,包括集群管理、应用部署、服务访问、网络配置、存储使用、安全保障等方面,旨在帮助用户快速解决使用过程中遇到的难题,提升容器管理和运维效率。
|
7天前
|
弹性计算 运维 Kubernetes
容器服务ACK常见问题之线上的K8s一直waiting如何解决
容器服务ACK(阿里云容器服务 Kubernetes 版)是阿里云提供的一种托管式Kubernetes服务,帮助用户轻松使用Kubernetes进行应用部署、管理和扩展。本汇总收集了容器服务ACK使用中的常见问题及答案,包括集群管理、应用部署、服务访问、网络配置、存储使用、安全保障等方面,旨在帮助用户快速解决使用过程中遇到的难题,提升容器管理和运维效率。
|
7天前
|
存储 Kubernetes 前端开发
容器服务ACK常见问题之把容器的时间改成宿主机的时区失败如何解决
容器服务ACK(阿里云容器服务 Kubernetes 版)是阿里云提供的一种托管式Kubernetes服务,帮助用户轻松使用Kubernetes进行应用部署、管理和扩展。本汇总收集了容器服务ACK使用中的常见问题及答案,包括集群管理、应用部署、服务访问、网络配置、存储使用、安全保障等方面,旨在帮助用户快速解决使用过程中遇到的难题,提升容器管理和运维效率。
|
7天前
|
Kubernetes 网络安全 调度
容器服务ACK常见问题之容器服务ACK的eci调度卡住如何解决
容器服务ACK(阿里云容器服务 Kubernetes 版)是阿里云提供的一种托管式Kubernetes服务,帮助用户轻松使用Kubernetes进行应用部署、管理和扩展。本汇总收集了容器服务ACK使用中的常见问题及答案,包括集群管理、应用部署、服务访问、网络配置、存储使用、安全保障等方面,旨在帮助用户快速解决使用过程中遇到的难题,提升容器管理和运维效率。

相关产品

  • 容器服务Kubernetes版