kubernetes快速入门-命令方式体验管理pod和service对象

命令方式操作pod和service

pod与service

手动使用命令运行一个名称为mynginx的pod

k8s@node01:~$ sudo kubectl  run mynginx --image=nginx:1.19.1-alpine --port=80 --replicas=1

Flag --replicas has been deprecated, has no effect and will be removed in the future.
pod/mynginx created 

--replicas在新版本中将被弃用掉。

查看pod的运行状态

k8s@node01:~$ sudo kubectl get pods -o wide
NAME      READY   STATUS    RESTARTS   AGE   IP           NODE     NOMINATED NODE   READINESS GATES
mynginx   1/1     Running   0          64s   10.244.2.2   node03   <none>           <none>

10.244.2.2表示mynginx这个pod的IP地址,并不是docker0网桥所在网络(172.17.0.0/16)的地址范围,而是flannel网络插件提供的网桥上的地址范围。这个pod还被调度到了node03这个节点上运行;再次强调pod是k8s调度的最小单位。

尝试访问nginx

k8s@node01:~$ curl http://10.244.2.2
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
# 能够正常访问

那pod的IP是否会重复?

当然不会,看一下node02与node03的关于flannel的接口

root@node02:~# ifconfig flannel.1
flannel.1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1450
        inet 10.244.1.0  netmask 255.255.255.255  broadcast 0.0.0.0
        ...

root@node03:~# ifconfig flannel.1
flannel.1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1450
        inet 10.244.2.0  netmask 255.255.255.255  broadcast 0.0.0.0
        ...

各个工作节点会自动 分配不同网段的地址范围,所以不会存在pod的IP会冲突。

pod地址只能在k8s集群内使用,k8s集群是pod地址能使用的边界,如果跳脱集群是不能能够访问的。

pod是有生命周期的,如果mynginx这个pod被删除后又被创建出来,那pod的IP地址就会发生改变,客户端要想再访问该pod上的服务就得再想办法知道其IP地址,而对一个pod来说,消亡和被创建会时常发生,所以直接使用pod的IP地址来访问其提供的服务是不可取的,这时就得给pod提供的服务给一个固定的访问端点,即service,service作为pod的客户端对外提供服务。

1.18新版本的k8s中在使用kubectl run创建一个pod时不再像老版本(1.11版本还有这样的特性)一样会默认创建一个deployment控制器,像1.18这种新版本在使用kubectl run时就只是创建一个pod而已,所以要想给pod一个固定的对外访问接口,需要按照以下操作

# 创建deployment
k8s@node01:~$ sudo kubectl create deployment mynginx-deployment --image=nginx:1.19.1-alpine
deployment.apps/mynginx-deployment created
k8s@node01:~$ sudo kubectl get deployment
NAME                 READY   UP-TO-DATE   AVAILABLE   AGE
mynginx-deployment   1/1     1            1           8s

# 查看deployment的详细信息
k8s@node01:~$ kubectl describe deployment mynginx-deployment
Name:                   mynginx-deployment
Namespace:              default
CreationTimestamp:      Thu, 23 Jul 2020 14:41:52 +0800
Labels:                 app=mynginx-deployment        # 标签
Annotations:            deployment.kubernetes.io/revision: 1
Selector:               app=mynginx-deployment   # 标签选择器
Replicas:               1 desired | 1 updated | 1 total | 1 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:  app=mynginx-deployment
  Containers:
   nginx:
    Image:        nginx:1.19.1-alpine
    Port:         <none>
    Host Port:    <none>
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  <none>
NewReplicaSet:   mynginx-deployment-646959f957 (1/1 replicas created)
Events:          <none>

# deployment创建后会自动创建pod,名称为"deployment名称-hash码"
k8s@node01:~$ kubectl get pods -o wide
NAME                                  READY   STATUS    RESTARTS   AGE   IP           NODE     NOMINATED NODE   READINESS GATES
mynginx-deployment-646959f957-rvhxk   1/1     Running   0          44s   10.244.2.5   node03   <none>           <none>

# 创建service,服务暴露
k8s@node01:~$ kubectl expose deployment/mynginx-deployment --name=nginx19 --type="ClusterIP" --port 80
service/nginx19 exposed

k8s@node01:~$ kubectl get services  # services可简写为svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP   22h
nginx19      ClusterIP   10.110.195.237   <none>        80/TCP    24s

# 查看services的详细信息
k8s@node01:~$ kubectl describe services nginx19
Name:              nginx19
Namespace:         default
Labels:            app=mynginx-deployment
Annotations:       <none>
Selector:          app=mynginx-deployment
Type:              ClusterIP
IP:                10.110.195.237
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.2.5:80
Session Affinity:  None
Events:            <none>

从service的详细信息中体现了一个service关联的后端(Endpoints)是什么地址,而这个地址为pod的地址。那pod与service是靠什么联系起来的呢?这里就是标签选择器提供的功能。从上边查看service的详细中可见Selector的值为app=mynginx-deployment,只要pod的标签中有这个标签,那此pod就会与该server相关联,用以下命令可查看pod的标签来验证

k8s@node01:~$ kubectl get pods --show-labels
NAME                                  READY   STATUS    RESTARTS   AGE   LABELS
mynginx-deployment-646959f957-rvhxk   1/1     Running   0          74m   app=mynginx-deployment,pod-template-hash=646959f957

现在就可使用service这个地址来访问pod提供的服务了

k8s@node01:~$ curl 10.110.195.237
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...

service地址虽说相对比较固定,但让客户端使用IP地址来访问也不方便,在k8s集群内部有一个组件叫coredns,它就可以自动解析server名称与IP的解析,再创建一个容器,在容器内部尝试使用server名称来访问服务

# 查看集群内dns地址
k8s@node01:~$ kubectl get svc -n kube-system
NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
kube-dns   ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   22h

k8s@node01:~$ kubectl run bboxclient --image=busybox -it --restart=Never
If you don't see a command prompt, try pressing enter.
/ # cat /etc/resolv.conf
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

/ # wget -O - -q nginx19
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>

可见,在k8s集群中,容器间通信的确可以通过server名称进行。

pod规模的动态变动

ikubernetes/myapp镜像是一个用于测试pod扩容,升级,回滚的镜像,镜像提供了一个主页和/hostname.html页面。

k8s@node01:~$ kubectl create deployment myapp-dep --image=ikubernetes/myapp:v1
deployment.apps/myapp-dep created
k8s@node01:~$ kubectl get pods -o wide
NAME                                  READY   STATUS    RESTARTS   AGE     IP           NODE     NOMINATED NODE   READINESS GATES
bboxclient                            1/1     Running   0          88s     10.244.2.9   node03   <none>           <none>
myapp-dep-c988cf69-cfppw              1/1     Running   0          9m16s   10.244.2.8   node03   <none>           <none>
mynginx-deployment-646959f957-rvhxk   1/1     Running   0          94m     10.244.2.5   node03   <none>           <none>

再到bboxclient这个pod中执行测试命令

k8s@node01:~$ kubectl run bboxclient --image=busybox /bin/sh -i -t
If you don't see a command prompt, try pressing enter.
/ # wget -O - -q 10.244.2.8  # 主面表明当前镜像的版本
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
/ #
/ # wget -O - -q 10.244.2.8/hostname.html  # 显示主机名,也是pod名称
myapp-dep-c988cf69-cfppw

创建service,暴露服务

k8s@node01:~$ kubectl expose deployment/myapp-dep --name=myapp --port=80
service/myapp exposed

k8s@node01:~$ kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP   23h
myapp        ClusterIP   10.102.57.245    <none>        80/TCP    36s
nginx19      ClusterIP   10.110.195.237   <none>        80/TCP    64m

# 在bboxclient测试
/ # wget -O - -q myapp
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
/ # wget -O - -q myapp/hostname.html
myapp-dep-c988cf69-cfppw

现在的状态是一个名为myapp的service下关联了一个名称为myapp-dep-c988cf69-cfppw的pod。service下的pod是可以进行动态变动的

k8s@node01:~$ kubectl scale --replicas=3 deployment/myapp-dep
deployment.apps/myapp-dep scaled

# 等一会后查看状态
k8s@node01:~$ kubectl get pods -o wide
NAME                                  READY   STATUS    RESTARTS   AGE    IP            NODE     NOMINATED NODE   READINESS GATES
bboxclient                            1/1     Running   0          40m    10.244.2.9    node03   <none>           <none>
myapp-dep-c988cf69-8kr4v              1/1     Running   0          108s   10.244.2.10   node03   <none>           <none>
myapp-dep-c988cf69-cfppw              1/1     Running   0          48m    10.244.2.8    node03   <none>           <none>
myapp-dep-c988cf69-cn5bf              1/1     Running   0          23m    10.244.1.4    node02   <none>           <none>
mynginx-deployment-646959f957-rvhxk   1/1     Running   0          132m   10.244.2.5    node03   <none>           <none>

k8s@node01:~$ kubectl get deployments
NAME                 READY   UP-TO-DATE   AVAILABLE   AGE
myapp-dep            3/3     3            3           48m
mynginx-deployment   1/1     1            1           133m

k8s@node01:~$ kubectl describe svc myapp
Name:              myapp
Namespace:         default
Labels:            app=myapp-dep
Annotations:       <none>
Selector:          app=myapp-dep
Type:              ClusterIP
IP:                10.102.57.245
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.1.4:80,10.244.2.10:80,10.244.2.8:80
Session Affinity:  None
Events:            <none>

再到bboxclient进行测试

/ # wget -O - -q myapp/hostname.html
myapp-dep-c988cf69-cfppw
/ # wget -O - -q myapp/hostname.html
myapp-dep-c988cf69-cfppw
/ # wget -O - -q myapp/hostname.html
myapp-dep-c988cf69-cn5bf
/ # wget -O - -q myapp/hostname.html
myapp-dep-c988cf69-8kr4v

# 多测试几次就发现service对后端关联的pod进行了随机调度

pod的滚动更新与回滚

现在对以ikubernetes/myapp:v1为镜像运行的pods(目前有3个副本),滚动升级为v2的版本

先在bboxclient中循环运行测试命令

/ # while true;do wget -O - -q myapp; sleep 1; done
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
...

更新镜像的命令语法为

Usage:
  kubectl set image (-f FILENAME | TYPE NAME) CONTAINER_NAME_1=CONTAINER_IMAGE_1 ... CONTAINER_NAME_N=CONTAINER_IMAGE_N

其中CONTAINER_NAME 表示容器的名称,可以通过kubectl describe pods POD_NAME来获取容器的名称

k8s@node01:~$ kubectl get pods -o wide
NAME                                  READY   STATUS    RESTARTS   AGE    IP            NODE     NOMINATED NODE   READINESS GATES
bboxclient                            1/1     Running   0          49m    10.244.2.9    node03   <none>           <none>
myapp-dep-c988cf69-8kr4v              1/1     Running   0          10m    10.244.2.10   node03   <none>           <none>
myapp-dep-c988cf69-cfppw              1/1     Running   0          57m    10.244.2.8    node03   <none>           <none>
myapp-dep-c988cf69-cn5bf              1/1     Running   0          32m    10.244.1.4    node02   <none>           <none>
mynginx-deployment-646959f957-rvhxk   1/1     Running   0          141m   10.244.2.5    node03   <none>           <none>

k8s@node01:~$ kubectl describe pod myapp-dep-c988cf69-8kr4v
...
Containers:
  myapp:   # 这个myapp就是容器的名称
    Container ID:   docker://3d41b77b5e52f7ed2536316c7242a2633f6a0c42bc0473bcce86da0ba84bbe2a
    Image:          ikubernetes/myapp:v1
    Image ID:       docker-pullable://ikubernetes/myapp@sha256:9c3dc30b5219788b2b8a4b065f548b922a34479577befb54b03330999d30d513
...

在k8s中,在同一个service下的各个pod的容器名称(仅限一个pod运行一个容器的情况)体现出来是一个相同的名称,并且此名称不是使用docker container ls命令查看到的名称。

开始镜像的滚动更新操作

k8s@node01:~$ kubectl set image deployment/myapp-dep myapp=ikubernetes/myapp:v2
deployment.apps/myapp-dep image updated

# bboxclient中观测
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
wget: can't connect to remote host (10.102.57.245): Connection refused
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>

从观测输出中可知,v1版本的镜像逐步被v2的镜像所替代,在这个过程中可以使用kubectl rollout status deployment myapp-dep命令查看滚动更新的过程。

如果更新后发现有问题,还可以进行回滚操作,同样可以使用kubectl set image的方式,如果是想直接回滚到升级前的版本,则可以直接使用kubectl rollout undo,如下

k8s@node01:~$ kubectl rollout undo deployment/myapp-dep
deployment.apps/myapp-dep rolled back

k8s@node01:~$ kubectl rollout status deployment myapp-dep
Waiting for deployment spec update to be observed...
Waiting for deployment "myapp-dep" rollout to finish: 0 out of 3 new replicas have been updated...
Waiting for deployment "myapp-dep" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "myapp-dep" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "myapp-dep" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "myapp-dep" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "myapp-dep" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "myapp-dep" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "myapp-dep" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "myapp-dep" rollout to finish: 1 old replicas are pending termination...
deployment "myapp-dep" successfully rolled out

集群外部访问service提供的服务

service的地址只能在集群内部(包括主机节点)进行访问,而服务名称则只能pod间能解析,如果集群外部想访问service服务,那需要在暴露服务时使用--type=NodePort,也可以动态修改service的状态

k8s@node01:~$ kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP   24h
myapp        ClusterIP   10.102.57.245    <none>        80/TCP    73m
nginx19      ClusterIP   10.110.195.237   <none>        80/TCP    136m
k8s@node01:~$ kubectl edit svc myapp
# 把
type: ClusterIP
# 修改为
type: NodePort
# 保存退出

k8s@node01:~$ kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP        24h
myapp        NodePort    10.102.57.245    <none>        80:32089/TCP   78m
nginx19      ClusterIP   10.110.195.237   <none>        80/TCP         141m

现在通过各个工作节点IP:32089就可以访问myapp提供的服务了。

k8s@node01:~$ curl node02:32089
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
k8s@node01:~$ curl node03:32089
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>

如果一个node节点挂了呢?所以在生产环境中应该在k8s集群外部使用nginx做一层代理,并实现高可用架构。

猜你喜欢

转载自blog.51cto.com/zhaochj/2531640