写在前面 接下来我们开始在Kubernetes简易环境中,来练习和使用一些常用的kubectl的命令,了解这些对于后续熟练和使用kubernetes有非常大的帮助。笔者将kubectl命令安装在了主节点上,因此接下来就在主节点上执行对应的kubectl命令。
(1)使用kubectl version
命令查看k8s的版本信息:
1 2 3 [root@server02 target]# · Client Version: version.Info{Major:"1", Minor:"9", GitVersion:"v1.9.0", GitCommit:"925c127ec6b946659ad0fd596fa959be43f0cc05", GitTreeState:"clean", BuildDate:"2017-12-15T21:07:38Z", GoVersion:"go1.9.2", Compiler:"gc", Platform:"linux/amd64"} Server Version: version.Info{Major:"1", Minor:"9", GitVersion:"v1.9.0", GitCommit:"925c127ec6b946659ad0fd596fa959be43f0cc05", GitTreeState:"clean", BuildDate:"2017-12-15T20:55:30Z", GoVersion:"go1.9.2", Compiler:"gc", Platform:"linux/amd64"}
(2)使用kubectl get nodes
命令查看k8s集群中所有的节点信息:
1 2 3 4 [root@server02 target]# kubectl get nodes NAME STATUS ROLES AGE VERSION 192.168.51.121 Ready <none> 24m v1.9.0 192.168.51.123 Ready <none> 24m v1.9.0
(3)使用kubectl get pods
命令查看k8s集群中所有的pods信息:
1 2 [root@server02 target]# kubectl get pods No resources found.
(4)使用kubectl --help
来查看所有kubectl所支持的命令及帮助信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 Basic Commands (Beginner): create Create a resource from a file or from stdin. expose 使用 replication controller, service, deployment 或者 pod 并暴露它作为一个 新的Kubernetes Service run 在集群中运行一个指定的镜像 set 为 objects 设置一个指定的特征 run-container 在集群中运行一个指定的镜像. This command is deprecated, use "run" instead Basic Commands (Intermediate): get 显示一个或更多 resources explain 查看资源的文档 edit 在服务器上编辑一个资源 delete Delete resources by filenames, stdin, resources and names, or by resources and label selector Deploy Commands: rollout Manage the rollout of a resource rolling-update 完成指定的 ReplicationController 的滚动升级 scale 为 Deployment, ReplicaSet, Replication Controller 或者 Job 设置一个新的副本数量 autoscale 自动调整一个 Deployment, ReplicaSet, 或者 ReplicationController 的副本数量 Cluster Management Commands: certificate 修改 certificate 资源. cluster-info 显示集群信息 top Display Resource (CPU/Memory/Storage) usage. cordon 标记 node 为 unschedulable uncordon 标记 node 为 schedulable drain Drain node in preparation for maintenance taint 更新一个或者多个 node 上的 taints Troubleshooting and Debugging Commands: describe 显示一个指定 resource 或者 group 的 resources 详情 logs 输出容器在 pod 中的日志 attach Attach 到一个运行中的 container exec 在一个 container 中执行一个命令 port-forward Forward one or more local ports to a pod proxy 运行一个 proxy 到 Kubernetes API server cp 复制 files 和 directories 到 containers 和从容器中复制 files 和 directories. auth Inspect authorization Advanced Commands: apply 通过文件名或标准输入流(stdin)对资源进行配置 patch 使用 strategic merge patch 更新一个资源的 field(s) replace 通过 filename 或者 stdin替换一个资源 convert 在不同的 API versions 转换配置文件 Settings Commands: label 更新在这个资源上的 labels annotate 更新一个资源的注解 completion Output shell completion code for the specified shell (bash or zsh) Other Commands: api-versions Print the supported API versions on the server, in the form of "group/version" config 修改 kubeconfig 文件 help Help about any command plugin Runs a command-line plugin version 输出 client 和 server 的版本信息
接下来我们尝试通过kubectl run
命令在k8s集群中部署一个命名为kubernetes-bootcamp的应用,Docker镜像通过--image
指定,--port
设置应用对外服务的端口,使用的命令如下:
1 $ kubectl run kubernetes-bootcamp --image=jocatalin/kubernetes-bootcamp:v1 --port=8080
然后我们查看一下所有应用的信息:
1 2 3 [root@server02 target]# kubectl get deployments NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE kubernetes-bootcamp 1 1 1 0 4m
再来查看一下所有Pod的信息:
1 2 3 [root@server02 target]# kubectl get pods NAME READY STATUS RESTARTS AGE kubernetes-bootcamp-5d7f968ccb-z59rw 0/1 ContainerCreating 0 5m
也可以使用如下命令查看所有pod的更多信息:
1 2 3 [root@server02 target]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE kubernetes-bootcamp-5d7f968ccb-z59rw 0/1 ContainerCreating 0 6m <none> 192.168.51.123
如果开发者希望删除某个deployment,此时可以使用如下命令,后面的kubernetes-bootcamp
则是应用的名称:
1 2 [root@server02 target]# kubectl delete deployments kubernetes-bootcamp deployment "kubernetes-bootcamp" deleted
其实kubernetes对一些命令也提供了一些别名,举个例子,假设当前使用的是kubectl get
命令,它可以显示一个或更多的resources,此时就可以使用kubectl get --help
查看后面所跟一些命令的别名。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 Valid resource types include: * all * certificatesigningrequests (aka 'csr') * clusterrolebindings * clusterroles * componentstatuses (aka 'cs') * configmaps (aka 'cm') * controllerrevisions * cronjobs * customresourcedefinition (aka 'crd') * daemonsets (aka 'ds') * deployments (aka 'deploy') * endpoints (aka 'ep') * events (aka 'ev') * horizontalpodautoscalers (aka 'hpa') * ingresses (aka 'ing') * jobs * limitranges (aka 'limits') * namespaces (aka 'ns') * networkpolicies (aka 'netpol') * nodes (aka 'no') * persistentvolumeclaims (aka 'pvc') * persistentvolumes (aka 'pv') * poddisruptionbudgets (aka 'pdb') * podpreset * pods (aka 'po') * podsecuritypolicies (aka 'psp') * podtemplates * replicasets (aka 'rs') * replicationcontrollers (aka 'rc') * resourcequotas (aka 'quota') * rolebindings * roles * secrets * serviceaccounts (aka 'sa') * services (aka 'svc') * statefulsets (aka 'sts') * storageclasses (aka 'sc') Examples: # List all pods in ps output format. kubectl get pods # List all pods in ps output format with more information (such as node name). kubectl get pods -o wide # List a single replication controller with specified NAME in ps output format. kubectl get replicationcontroller web # List a single pod in JSON output format. kubectl get -o json pod web-pod-13je7 # List a pod identified by type and name specified in "pod.yaml" in JSON output format. kubectl get -f pod.yaml -o json # Return only the phase value of the specified pod. kubectl get -o template pod/web-pod-13je7 --template={{.status.phase}} # List all replication controllers and services together in ps output format. kubectl get rc,services # List one or more resources by their type and names. kubectl get rc/web service/frontend pods/web-pod-13je7 # List all resources with different types. kubectl get all
例如,查看所有应用的信息所使用的命令,可由
1 $ kubectl get deployments
简化为如下的:
我们再来看一下查看所有pod的更多信息:
1 2 3 [root@server02 ~]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE kubernetes-bootcamp-6b7849c495-mgzpp 1/1 Running 0 22h 172.20.40.194 192.168.51.123
如果想要查看k8s的日志运行信息,可以使用journalctl -f
命令。可以使用kubectl describe deploy +应用名称
命令来查看某个应用的信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 [root@server02 ~]# kubectl describe deploy kubernetes-bootcamp Name: kubernetes-bootcamp Namespace: default CreationTimestamp: Mon, 29 Aug 2022 22:30:58 +0800 Labels: run=kubernetes-bootcamp Annotations: deployment.kubernetes.io/revision=1 Selector: run=kubernetes-bootcamp Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable StrategyType: RollingUpdate MinReadySeconds: 0 RollingUpdateStrategy: 1 max unavailable, 1 max surge Pod Template: Labels: run=kubernetes-bootcamp Containers: kubernetes-bootcamp: Image: jocatalin/kubernetes-bootcamp:v1 Port: 8080/TCP Environment: <none> Mounts: <none> Volumes: <none> Conditions: Type Status Reason ---- ------ ------ Available True MinimumReplicasAvailable OldReplicaSets: <none> NewReplicaSet: kubernetes-bootcamp-6b7849c495 (1/1 replicas created) Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ScalingReplicaSet 22h deployment-controller Scaled up replica set kubernetes-bootcamp-6b7849c495 to 1
我们再来看一下查看所有pod信息:
1 2 3 [root@server02 ~]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE kubernetes-bootcamp-6b7849c495-mgzpp 1/1 Running 0 22h 172.20.40.194 192.168.51.123
再来看一下这个Pod的信息,可使用kubectl describe pods +pod名称
命令:
基础命令的学习就到此结束了,接下来我们继续学习其他的知识。deployment已经创建起来了,我们该如何去访问它呢?第一种方式是使用kubectl proxy
命令 ,它会在本地监听8001端口,这个主要用于测试:
1 2 [root@server02 ~]# kubectl proxy Starting to serve on 127.0.0.1:8001
然后我们就可以通过这个REST API来访问这个集群中运行的每一个服务。可以新开一个终端,在里面先查看一下当前所有的pods信息:
1 2 3 [root@server02 ~]# kubectl get pods NAME READY STATUS RESTARTS AGE kubernetes-bootcamp-6b7849c495-mgzpp 1/1 Running 1 1d
然后我们再来通过REST API访问这个pod,使用的命令如下:
1 2 [root@server02 ~]# curl http://localhost:8001/api/v1/proxy/namespaces/default/pods/kubernetes-bootcamp-6b7849c495-mgzpp/ Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-6b7849c495-mgzpp | v=1
这样我们就成功的访问了这个服务。接着我们停掉这个kubectl proxy
,开始学习扩缩容相关内容。首先我们查看一下当前所有的deployments信息:
1 2 3 [root@server02 ~]# kubectl get deploy NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE kubernetes-bootcamp 1 1 1 1 1d
接着我们来对这个deployments进行扩缩容,设置4个副本数,使用的命令如下:
1 2 [root@server02 ~]# kubectl scale deploy kubernetes-bootcamp --replicas=4 deployment "kubernetes-bootcamp" scaled
然后我们来看一下当前所有的pods信息:
1 2 3 4 5 6 [root@server02 ~]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE kubernetes-bootcamp-6b7849c495-85bvf 1/1 Running 0 3m 172.20.188.1 192.168.51.121 kubernetes-bootcamp-6b7849c495-ddcnq 1/1 Running 0 3m 172.20.188.2 192.168.51.121 kubernetes-bootcamp-6b7849c495-mgzpp 1/1 Running 1 1d 172.20.40.195 192.168.51.123 kubernetes-bootcamp-6b7849c495-nqwdv 1/1 Running 0 3m 172.20.40.196 192.168.51.123
现在4个实例都已经启动了,可以看到在121上运行了2个实例,在123上也运行了2个实例,也就是说Kubernetes会尽可能的分散资源,不会在一台机器上运行很多,而在另一台机器上运行很少。接下来我们使用同样的命令,将其缩容为2个:
1 2 [root@server02 ~]# kubectl scale deploy kubernetes-bootcamp --replicas=2 deployment "kubernetes-bootcamp" scaled
之后再来查看一下当前所有的pods信息:
1 2 3 4 [root@server02 ~]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE kubernetes-bootcamp-6b7849c495-mgzpp 1/1 Running 1 1d 172.20.40.195 192.168.51.123 kubernetes-bootcamp-6b7849c495-nqwdv 1/1 Running 0 10m 172.20.40.196 192.168.51.123
接下来学习如何更新镜像,首先查看一下当前列表中所有的deployments信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 [root@server02 ~]# kubectl describe deployments Name: kubernetes-bootcamp Namespace: default CreationTimestamp: Mon, 29 Aug 2022 22:30:58 +0800 Labels: run=kubernetes-bootcamp Annotations: deployment.kubernetes.io/revision=1 Selector: run=kubernetes-bootcamp Replicas: 2 desired | 2 updated | 2 total | 2 available | 0 unavailable StrategyType: RollingUpdate MinReadySeconds: 0 RollingUpdateStrategy: 1 max unavailable, 1 max surge Pod Template: Labels: run=kubernetes-bootcamp Containers: kubernetes-bootcamp: Image: jocatalin/kubernetes-bootcamp:v1 Port: 8080/TCP Environment: <none> Mounts: <none> Volumes: <none> Conditions: Type Status Reason ---- ------ ------ Available True MinimumReplicasAvailable OldReplicaSets: <none> NewReplicaSet: kubernetes-bootcamp-6b7849c495 (2/2 replicas created) Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ScalingReplicaSet 12m deployment-controller Scaled up replica set kubernetes-bootcamp-6b7849c495 to 4 Normal ScalingReplicaSet 4m deployment-controller Scaled down replica set kubernetes-bootcamp-6b7849c495 to 2
可以看到这个名为kubernetes-bootcamp的deployments所使用的的镜像为jocatalin/kubernetes-bootcamp:v1
,接下来我们尝试更新这个镜像:
1 2 [root@server02 ~]# kubectl set image deploy kubernetes-bootcamp kubernetes-bootcamp=jocatalin/kubernetes-bootcamp:v2 deployment "kubernetes-bootcamp" image updated
注意使用这个命令的时候,默认deployment的名称和容器的名称是一样的。然后使用如下命令来查看命令的更新结果:
1 2 [root@server02 ~]# kubectl rollout status deploy kubernetes-bootcamp deployment "kubernetes-bootcamp" successfully rolled out
从执行结果中可以看出它更新成功了,然后我们继续使用kubectl describe deployments
命令来确认已经更新成功:
如果开发者对某一deployment执行了错误的命令,现在想回滚到上一步的操作状态,说白了就是撤销当前的操作,可以使用kubectl rollout undo deploy +deployment的名称
这一命令。之后可以使用kubectl rollout status deploy +deployment的名称
这一命令来查看当前执行状态。
上面学习的都是使用命令来管理服务,但是当服务较多时,还使用命令就显得捉襟见肘了,此时就可以通过配置文件来进行管理。
回到主节点所在机器上,在/home/envy
目录下新建一个名为services的目录,然后在这个services目录中新建一个名为nginx-pod.yaml
文件。一般来说,我们都会使用yaml格式的文件来创建k8s服务的配置文件。nginx-pod.yaml
文件里面的内容如下所示:
1 2 3 4 5 6 7 8 9 10 apiVersion: v1 kind: Pod metadata: name: nginx spec: containers: - name: nginx image: nginx:1.7.9 ports: - containerPort: 80
以下是对上述配置文件中一些配置项的说明:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 # 版本号 apiVersion: v1 # 类型 kind: Pod # 元数据 metadata: name: nginx # 比较特别的配置 spec: containers: # 容器 - name: nginx # 容器名称 image: nginx:1.7.9 # 容器所使用的镜像版本信息 ports: - containerPort: 80 # 容器端口
然后我们尝试使用kubectl create
命令从指定文件或者输入中创建一个资源,当然这里就是从nginx-pod.yaml
配置文件中来创建一个名为nginx的Pod:
1 2 [root@server02 services]# kubectl create -f nginx-pod.yaml pod "nginx" created
然后我们来看一下这个Pod的信息:
1 2 3 4 5 [root@server02 services]# kubectl get pods NAME READY STATUS RESTARTS AGE kubernetes-bootcamp-7689dc585d-rlz44 1/1 Running 0 1h kubernetes-bootcamp-7689dc585d-z2678 1/1 Running 0 1h nginx 0/1 ImagePullBackOff 0 1m
我们再来看一下deployment,可以发现不存在新的deployment,这是因为我们创建的是一个Pod,一个Pod就是一个Pod,这个和deployment没有任何关系:
1 2 3 [root@server02 services]# kubectl get deploy NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE kubernetes-bootcamp 2 2 2 2 1d
但是当我们使用kubectl run
命令时,它会创建一个deployment,而不只是仅仅创建一个Pod而已。
再来看一下当前所有的Pods,可以看到我们前面创建的Pods已经创建完成并启动了:
1 2 3 4 NAME READY STATUS RESTARTS AGE kubernetes-bootcamp-7689dc585d-rlz44 1/1 Running 0 1h kubernetes-bootcamp-7689dc585d-z2678 1/1 Running 0 1h nginx 1/1 Running 0 1m
现在问题来了,我们该如何去访问这个nginx呢?还是采用之前的方式,在当前窗口执行kubectl proxy
命令,然后新开一个终端执行如下命令:
1 [root@server02 ~]# curl http://localhost:8001/api/v1/proxy/namespaces/default/pods/nginx/
接下来我们尝试创建一个nginx的deployment,在/home/envy/services
目录中新建一个名为nginx-deployment.yaml
的配置文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 apiVersion: apps/v1beta1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 2 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.7.9 ports: - containerPort: 80
以下是对上述配置文件中一些配置项的说明:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 # 版本号,注意固定格式 apiVersion: apps/v1beta1 # 类型 kind: Deployment # 元数据 metadata: name: nginx-deployment # 比较特别的配置 spec: replicas: 2 # 两个副本 template: # 模板信息 metadata: #模板元数据 labels: # 标签 app: nginx spec: # 比较特别的配置 containers: # 容器 - name: nginx # 容器名称 image: nginx:1.7.9 # 容器所使用的镜像版本信息 ports: - containerPort: 80 # 容器端口
之后我们继续使用之前的命令来创建一个deployment:
1 2 [root@server02 services]# kubectl create -f nginx-deployment.yaml deployment "nginx-deployment" created
然后我们查看一下当前所有的deployments,使用的命令如下:
1 2 3 4 [root@server02 services]# kubectl get deploy NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE kubernetes-bootcamp 2 2 2 2 1d nginx-deployment 2 2 2 1 1m
可以看到这个nginx-deployment
目前只有一个,因为它正在去另一个服务器上下载,目前只有一个节点下载了这个镜像。然后我们还可以查看一下所有的pods:
1 2 3 4 5 6 7 [root@server02 services]# kubectl get pods NAME READY STATUS RESTARTS AGE kubernetes-bootcamp-7689dc585d-rlz44 1/1 Running 0 1h kubernetes-bootcamp-7689dc585d-z2678 1/1 Running 0 1h nginx 1/1 Running 0 31m nginx-deployment-6c54bd5869-q5z6c 0/1 ImagePullBackOff 0 3m nginx-deployment-6c54bd5869-rt4zh 1/1 Running 0 3m
这里主要关心以nginx-deployment
开头的两个deployment,可以看到一个正在运行,另一个正在拉取镜像。我们还可以使用如下命令来查看指定标签的Pods:
1 2 3 4 [root@server02 services]# kubectl get pods -l app=nginx NAME READY STATUS RESTARTS AGE nginx-deployment-6c54bd5869-q5z6c 0/1 ImagePullBackOff 0 5m nginx-deployment-6c54bd5869-rt4zh 1/1 Running 0 5m
可以看到这里就只是查看以app=nginx为标签的pods的信息,service的原理其实也是根据这个label(标签)来筛选出它所想要服务的Pod,然后实现一个负载均衡。
最后可以看到这两个以app=nginx为标签的pods已经成功启动了:
1 2 3 4 [root@server02 services]# kubectl get pods -l app=nginx NAME READY STATUS RESTARTS AGE nginx-deployment-6c54bd5869-q5z6c 1/1 Running 0 10m nginx-deployment-6c54bd5869-rt4zh 1/1 Running 0 10m
接下来我们尝试在这基础的集群之上,再给它添加两个功能,也就是kube-proxy和kube-dns。当开发者需要给集群增加service功能,此时就需要增加kube-proxy组件;当需要dns,通过名称解析服务这样的功能,此时就可以增加kube-dns组件。k8s会把一些不必要的功能做成一个组件,这样有效的降低了各个组件之间的耦合程度。
给集群增加service功能–kube-proxy(工作节点执行) 简介 每台工作节点上都应该运行一个kube-proxy服务,它负责监听APIServer中service和endpoint的变化,并通过iptables等来为服务配置负载均衡,是让服务在集群外可以被访问到的重要方式。
部署 kube-proxy的部署方式也是通过系统服务,部署流程跟etcd完全一样,操作如下:
1 2 3 4 5 6 7 8 9 10 11 12 # 确保工作目录存在 $ mkdir -p /var/lib/kube-proxy #复制kube-proxy服务配置文件到系统服务目录 $ cp /home/envy/kubernetes-starter/target/worker-node/kube-proxy.service /lib/systemd/system/ #复制kube-proxy依赖的配置文件 $ cp /home/envy/kubernetes-starter/target/worker-node/kube-proxy.kubeconfig /etc/kubernetes/ #enable服务 $ systemctl enable kube-proxy.service # 启动服务 $ service kube-proxy start # 查看服务日志,看是否有错误信息,确保服务正常 $ journalctl -f -u kube-proxy.service
然后我们查看一下监听的端口号,看到10249和10256端口都是正常启动的,说明配置是成功的。
接下来我们看一下这个kube-proxy.service
文件的内容,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 [Unit] Description=Kubernetes Kube-Proxy Server Documentation=https://github.com/GoogleCloudPlatform/kubernetes After=network.target [Service] WorkingDirectory=/var/lib/kube-proxy ExecStart=/home/envy/bin/kube-proxy \ --bind-address=192.168.51.121 \ --hostname-override=192.168.51.121 \ --kubeconfig=/etc/kubernetes/kube-proxy.kubeconfig \ --logtostderr=true \ --v=2 Restart=on-failure RestartSec=5 LimitNOFILE=65536 [Install] WantedBy=multi-user.target
这里主要关注Service部分,其中WorkingDirectory是kube-proxy的工作目录,ExecStart是启动的命令,/home/envy/bin/kube-proxy
则是需要启动的程序名称,通过--bind-address
参数来设置监听的地址,kubeconfig
则是它所依赖的配置文件,描述了kube-proxy如何访问api-server。
下面是kube-proxy.kubeconfig
配置文件的内容,它配置了kube-proxy如何访问api-server,内容与kubelet雷同,不再赘述。
1 2 3 4 5 6 7 8 9 10 11 12 13 apiVersion: v1 clusters: - cluster: server: http://192.168.51.122:8080 name: kubernetes contexts: - context: cluster: kubernetes name: default current-context: default kind: Config preferences: {} users: []
这样我们就给集群添加了kube-proxy,那么问题来了,我们该如何使用它呢?往下看,回到主节点,首先使用如下命令来查看所有的服务:
1 2 3 [root@server02 services]# kubectl get services NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.68.0.1 <none> 443/TCP 3d
注意这个服务是APIServer在启动的时候就默认创建的服务,它的作用是什么呢?我们先看一下它有什么东西:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 [root@server02 services]# kubectl describe service kubernetes Name: kubernetes Namespace: default Labels: component=apiserver provider=kubernetes Annotations: <none> Selector: <none> Type: ClusterIP IP: 10.68.0.1 Port: https 443/TCP TargetPort: 6443/TCP Endpoints: 192.168.51.122:6443 Session Affinity: ClientIP Events: <none>
可以看到它的Type是ClusterIP,而且IP地址为10.68.0.1,相当于给APIServer做成了一个服务,它有什么作用呢?第一,集群内其他的组件可通过这个IP来访问到APIServer,这样它就不需要依赖于具体的IP地址;第二,负载均衡,它可以用来负责APIServer这一组件的高可用,当然前提是我们有多个APIServer实例的时候,然后他就可以通过这个Server IP来实现负载均衡,并且会自动过滤掉不可用的节点,进而实现APIServer的高可用。
其实我们自己也可以创建service,首先查看一下当前所有的deployments:
1 2 3 4 [root@server02 ~]# kubectl get deployments NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE kubernetes-bootcamp 2 2 2 2 2d nginx-deployment 2 2 2 2 23h
可以看到这里有两个deployments,之前我们访问这两个deployments的时候,使用的都是代理的方式,即kubectl proxy
,开一个HTTP的EndPoint,然后通过这个EndPoint的地址去访问这个Pod。接下来我们看看kube-proxy如何给我们带来方便,让我们如何访问这个Pod。可使用如下命令:
1 2 [root@server02 ~]# kubectl expose deploy kubernetes-bootcamp --type="NodePort" --target-port=8080 --port=80 service "kubernetes-bootcamp" exposed
该命令说明为kubectl expose deploy deployment名称 --type="NodePort" --target-port=容器端口 --port=Service端口
,接着我们再次使用之前的命令来获取当前所有的service:
1 2 3 4 [root@server02 ~]# kubectl get services NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.68.0.1 <none> 443/TCP 3d kubernetes-bootcamp NodePort 10.68.37.19 <none> 80:30735/TCP 1m
可以看到这里多了一个service,它的类型为NodePort,所分配的IP地址为10.68.37.19,注意这里的端口映射,将80端口映射到30735,这个30735是随机的端口号,查看一下这个30735端口是否为监听端口:
1 2 [root@server02 ~]# netstat -ntlp|grep 30735 [root@server02 ~]#
可以看到这个30735不是监听端口,但是这个端口应该是监听端口才是,为什么这里没有监听呢?是因为当前节点是master节点,而不是工作节点,它并没有kube-proxy。我们去另一台机器,如123机器,反正只要是工作节点就可以,之后查看 一下这台机器上的30735端口是否为监听端口,可以看到它确实是监听者。
这个30735是随机的端口号,也就是kube-proxy实际在节点上启动的一个端口,可以通过这个端口来访问我们的服务。上述命令中的target-port
则是当前容器,也就是Pod它真正提供服务的端口,也就是说这个容器实际上监听的端口是8080。port则是我们在这个CLUSTER-IP虚拟IP上去访问这个服务的时候需要提供的端口,这里提供的则是80端口。也就是说此时我们可以通过Service的CLUSTER-IP加上80服务端口,或者是通过NodeIP+NodePort去访问这个服务,这是两种方式。
接下来我们看一下当前所有的Pod信息:
1 2 3 4 5 6 7 [root@server02 ~]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE kubernetes-bootcamp-7689dc585d-x7bft 1/1 Running 0 55m 172.20.188.12 192.168.51.121 kubernetes-bootcamp-7689dc585d-z2678 1/1 Running 2 2d 172.20.188.10 192.168.51.121 nginx 1/1 Running 2 1d 172.20.188.9 192.168.51.121 nginx-deployment-6c54bd5869-chjwn 1/1 Running 0 55m 172.20.188.13 192.168.51.121 nginx-deployment-6c54bd5869-rt4zh 1/1 Running 2 1d 172.20.188.11 192.168.51.121
从原理上来说,上述pod列表中的任意一个pod所包含的容器,都是可以访问到CLUSTER-IP,并且它们之间也都是可以互相连通的,这是Kubernetes在设计上所做的要求,前提是我们的环境是正常的。此处以192.168.51.121节点上容器为例,我们查看其中包含bootcamp的容器,可以看到它有多个,选择一个id为0b4380c9fb67的容器,并进入到该容器,直接访问CLUSTER-IP加上80端口,可以看到它是可以访问这个服务的:
1 2 [root@server01 ~]# docker exec -it 0b4380c9fb67 bash root@kubernetes-bootcamp-7689dc585d-x7bft:/# curl 10.68.37.19:80
同样的我们可以在这个容器中尝试看一下是否可以连通其他的Pod,可以选择之前的nginx,它的IP地址为172.20.188.9,可以看到访问结果如下:
回到主节点,在前面我们创建的服务,它的NodePort是随机的,也就是前面多次提到的30735,我们希望将这个端口给固定下来,即我们给它指定一个NodePort,这也是可以的,但是需要我们通过配置文件的方式来进行设置。
截止到目前,/home/envy/services
目录下已经有两个配置文件了:
1 2 [root@server02 services]# ls nginx-deployment.yaml nginx-pod.yaml
接下来我们创建一个新的配置文件,名为nginx-service.yaml
,里面的内容如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 apiVersion: v1 kind: Service metadata: name: nginx-service spec: ports: - port: 8080 targetPort: 80 nodePort: 20000 selector: app: nginx type: NodePort
以下是对上述配置文件中一些配置项的说明:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 # 版本号,注意固定格式 apiVersion: v1 # 类型 kind: Service # 元数据 metadata: name: nginx-service # 比较特别的配置 spec: ports: # 端口 - port: 8080 # Service端口(即CLUSTRER_IP所对应的端口) targetPort: 80 # 容器端口(即具体的Nginx服务所对应的端口) nodePort: 20000 # 节点端口(即能对节点外部提供服务的端口) selector: # 给谁提供这样的服务,需要指定具体的Pod app: nginx # 通过app=nginx进行指定 type: NodePort # 类型,默认的类型是CLUSTRER_IP,此处使用NodePort
之后我们继续使用之前的命令来创建一个service:
1 2 [root@server02 services]# kubectl create -f nginx-service.yaml service "nginx-service" created
然后我们再来查看当前所有的service:
1 2 3 4 5 [root@server02 services]# kubectl get services NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.68.0.1 <none> 443/TCP 5d kubernetes-bootcamp NodePort 10.68.37.19 <none> 80:30735/TCP 1d nginx-service NodePort 10.68.235.19 <none> 8080:20000/TCP 1m
可以看到这里多了一个名为nginx-service的service,而且类型为NodePort,它也有一个CLUSTER-IP,重要的是它的端口映射为8080:20000,即8080为服务的端口,而20000则是节点的端口。然后我们尝试在主节点,使用192.168.51.121:2000
来访问121工作节点的nginx服务,可以看到可以访问成功了。同理也可以使用192.168.51.123:2000
来访问123工作节点的nginx服务,这也是可以的。通过命令和配置文件方式创建出来的service都是一样的,没有任何区别,只是Kubernetes给我们提供了不同的操作方式而已。
给集群增加dns功能–kube-dns(以app方式启动) 简介 kube-dns为Kubernetes集群提供命名服务,主要用于解析集群服务名和Pod的hostname,目的是让pod可以通过名字访问到集群内的服务。它通过添加A记录的方式实现名字和service的解析,其中普通的service会解析到service-ip,而headless的service则会解析到pod列表,并且实现负载均衡。
部署 kube-dns则是通过Kubernetes应用的方式进行部署,其中我们之前生成的target文件里面kube-dns.yaml
的配置文件与官方基本上一致,除了镜像名称不同而已。
kube-dns这个服务比较特殊的一点在于它的namespace为kube-system,而不是main这个空间中。这个服务所涉及到的东西比较多,如果我们手动创建它的配置文件,这其实是很难的,一般做法是直接使用官方提供的文件,然后在里面根据实际情况进行配置,多个组件之间使用---
进行区分。
查看一下这个/home/envy/kubernetes-starter/target/services/kube-dns.yaml
配置文件中的信息,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 --- #ConfigMap是我们见到的一个新类型,顾名思义是做配置管理的,这里用作kube-dns配置存储 apiVersion: v1 kind: ConfigMap metadata: name: kube-dns namespace: kube-system labels: addonmanager.kubernetes.io/mode: EnsureExists --- #认证授权使用,这里未用到 apiVersion: v1 kind: ServiceAccount metadata: name: kube-dns namespace: kube-system labels: addonmanager.kubernetes.io/mode: Reconcile --- #dns服务 apiVersion: v1 kind: Service metadata: name: kube-dns namespace: kube-system labels: k8s-app: kube-dns addonmanager.kubernetes.io/mode: Reconcile kubernetes.io/name: "KubeDNS" spec: selector: #选择器,一个服务包含了哪些pods k8s-app: kube-dns #服务的clusterip,需要跟kubelet保持一致 clusterIP: 10.68.0.2 ports: - name: dns port: 53 protocol: UDP - name: dns-tcp port: 53 protocol: TCP --- #具体的pod定义,包含了三个容器 apiVersion: apps/v1 kind: Deployment metadata: name: kube-dns namespace: kube-system labels: k8s-app: kube-dns addonmanager.kubernetes.io/mode: Reconcile spec: strategy: rollingUpdate: maxSurge: 10% maxUnavailable: 0 selector: matchLabels: k8s-app: kube-dns template: metadata: labels: k8s-app: kube-dns annotations: scheduler.alpha.kubernetes.io/critical-pod: '' spec: tolerations: - key: "CriticalAddonsOnly" operator: "Exists" volumes: - name: kube-dns-config configMap: name: kube-dns optional: true containers: #实现dns解析功能 - name: kubedns image: registry.cn-hangzhou.aliyuncs.com/imooc/k8s-dns-kube-dns-amd64:1.14.5 resources: # TODO: Set memory limits when we've profiled the container for large # clusters, then set request = limit to keep this container in # guaranteed class. Currently, this container falls into the # "burstable" category so the kubelet doesn't backoff from restarting it. limits: memory: 170Mi requests: cpu: 100m memory: 70Mi livenessProbe: httpGet: path: /healthcheck/kubedns port: 10054 scheme: HTTP initialDelaySeconds: 60 timeoutSeconds: 5 successThreshold: 1 failureThreshold: 5 readinessProbe: httpGet: path: /readiness port: 8081 scheme: HTTP # we poll on pod startup for the Kubernetes master service and # only setup the /readiness HTTP server once that's available. initialDelaySeconds: 3 timeoutSeconds: 5 args: - --domain=cluster.local. - --dns-port=10053 - --config-dir=/kube-dns-config #访问kube-apiserver的地址 - --kube-master-url=http://192.168.51.122:8080 - --v=2 env: - name: PROMETHEUS_PORT value: "10055" ports: - containerPort: 10053 name: dns-local protocol: UDP - containerPort: 10053 name: dns-tcp-local protocol: TCP - containerPort: 10055 name: metrics protocol: TCP volumeMounts: - name: kube-dns-config mountPath: /kube-dns-config #dnsmasq类似一个dns缓存,用于提高访问效率 - name: dnsmasq image: registry.cn-hangzhou.aliyuncs.com/imooc/k8s-dns-dnsmasq-nanny-amd64:1.14.5 livenessProbe: httpGet: path: /healthcheck/dnsmasq port: 10054 scheme: HTTP initialDelaySeconds: 60 timeoutSeconds: 5 successThreshold: 1 failureThreshold: 5 args: - -v=2 - -logtostderr - -configDir=/etc/k8s/dns/dnsmasq-nanny - -restartDnsmasq=true - -- - -k - --cache-size=1000 - --log-facility=- - --server=/cluster.local./127.0.0.1#10053 - --server=/in-addr.arpa/127.0.0.1#10053 - --server=/ip6.arpa/127.0.0.1#10053 ports: - containerPort: 53 name: dns protocol: UDP - containerPort: 53 name: dns-tcp protocol: TCP # see: https://github.com/kubernetes/kubernetes/issues/29055 for details resources: requests: cpu: 150m memory: 20Mi volumeMounts: - name: kube-dns-config mountPath: /etc/k8s/dns/dnsmasq-nanny #sidecar是一个监控功能,负责监控另外两个容器的运行 - name: sidecar image: registry.cn-hangzhou.aliyuncs.com/imooc/k8s-dns-sidecar-amd64:1.14.5 livenessProbe: httpGet: path: /metrics port: 10054 scheme: HTTP initialDelaySeconds: 60 timeoutSeconds: 5 successThreshold: 1 failureThreshold: 5 args: - --v=2 - --logtostderr - --probe=kubedns,127.0.0.1:10053,kubernetes.default.svc.cluster.local.,5,A - --probe=dnsmasq,127.0.0.1:53,kubernetes.default.svc.cluster.local.,5,A ports: - containerPort: 10054 name: metrics protocol: TCP resources: requests: memory: 20Mi cpu: 10m dnsPolicy: Default # Don't use cluster DNS. serviceAccountName: kube-dns
之后执行如下命令即可启动kube-dns服务:
1 $ kubectl create -f /home/envy/kubernetes-starter/target/services/kube-dns.yaml
可以看到输出信息如下:
1 2 3 4 5 [root@server02 services]# kubectl create -f /home/envy/kubernetes-starter/target/services/kube-dns.yaml configmap "kube-dns" created serviceaccount "kube-dns" created service "kube-dns" created deployment "kube-dns" created
configMap用于配置管理,serviceaccount也是一种类型,主要用于Kubernetes的认证与授权,这里未使用到。
然后我们就可以使用如下命令来查看这个名为kube-system的namespace中的服务信息:
1 2 3 [root@server02 services]# kubectl -n kube-system get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kube-dns ClusterIP 10.68.0.2 <none> 53/UDP,53/TCP 3m
可以看到这里面有一个CLUSTER-IP,这个就是之前我们在创建kubelet的时候所配置的地址,这样在使用kube-dns的时候它就会自动生效。注意我们在kube-dns的yaml配置文件中也需要配置一个与它完全一样的地址。
再来看一下这个名为kube-system的namespace中的deployment信息:
1 2 3 [root@server02 ~]# kubectl -n kube-system get deploy NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE kube-dns 1 1 1 1 9h
然后看一下这个名为kube-system的namespace中的pod信息:
1 2 3 [root@server02 ~]# kubectl -n kube-system get pods NAME READY STATUS RESTARTS AGE kube-dns-7d7b4f767d-6xnnm 3/3 Running 3 9h
可以看到这个Pod中运行了三个容器,它们都是Running状态,接下来我们看一下这些容器运行在哪些机器上:
1 2 3 [root@server02 ~]# kubectl -n kube-system get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE kube-dns-7d7b4f767d-6xnnm 3/3 Running 3 9h 172.20.40.202 192.168.51.123
可以看到它们都运行在192.168.51.123这台机器上,接下来我们我们先查看这个192.168.51.123机器上运行的容器,然后进入到某一容器中,使用curl nginx-service:8080
来访问之前创建的名为nginx-service的service。可以看到它是可以访问的,这就说明dns确实给我们提供了解析的功能,通过名字解析到了对应的CLUSTER-IP。也就是说其实它最终访问的还是CLUSTER-IP:SERVICED_PORT
。然后我们还可以查看当前容器的dns配置文件:
1 2 3 4 root@kubernetes-bootcamp-7689dc585d-x7bft:/# cat /etc/resolv.conf nameserver 10.68.0.2 search default.svc.cluster.local. svc.cluster.local. cluster.local. options ndots:5
可以看到它第一个nameserver的值就是10.68.0.2,实际上就是通过这个值来解析的,这也可以证实为什么我们通过名字就可以映射到CLUSTER-IP。