Kubernetes(三)实战入门
实战入门
本章介绍如何在kubernetes集群中部署一个nginx服务,并能够对其进行访问。
1. Namespace
Namespace主要作用是实现多套环境的资源隔离或者多租户的资源隔离。
默认情况下,kubernetes 集群中的所有Pod都是可以相互访问的。但是在实际中,可能不希望让2个Pod之间进行相互访问,此时即可将两个Pod划分到不同的namespace下。Kubernetes通过将集群内部的资源分配到不同的Namespace中,可以形成逻辑上的“组”,以方便不同的组的资源进行隔离使用和管理。
可以通过kubernetes的授权机制,将不同的namespace交给不同租户进行管理。这样就实现了多租户的资源隔离。此时还能结合kubernetes的资源配额机制,限定不同租户能占用的资源,例如CPU使用量、内存使用量等,来实现租户可用资源的管理。
例如可以给namespace-dev 的 ns 分配5GB的内存资源,而namespace-test 只分配3GB的资源。
Kubernetes集群在创建后,会默认创建几个namespaces:
$ kubectl get ns NAME STATUS AGE default Active 22h # 所有未指定Namespace的对象都会被分配在default 命名空间 kube-node-lease Active 22h # 集群节点之间的心跳维护,v1.13 开始引入 kube-public Active 22h # 此命名空间下的资源可以被所有人访问(包括未认证用户) kube-system Active 22h # 所有由kubernetes 系统创建的资源都处于这个命名空间
下面是 namespaces 的资源操作示例:
# 查看 $ kubectl get ns kube-system NAME STATUS AGE kube-system Active 23h => Active 表示命名空间正在使用;另一种状态是Terminating :表示正在删除命名空间 # 描述 $ kubectl describe ns default Name: default Labels: <none> Annotations: <none> Status: Active No resource quota. => ResourceQuota 针对namespace做的资源限制 No LimitRange resource. => LimitRange 针对namespace中的每个组件做的资源限制 # 创建 $ kubectl create ns dev namespace/dev created # 删除 $ kubectl delete ns dev namespace "dev" deleted #配置方式 首先准备一个 yaml 文件:ds-dev.yaml $ cat yamls/ns-dev.yaml apiVersion: v1 kind: Namespace metadata: name: dev $ kubectl apply -f yamls/ns-dev.yaml namespace/dev created $ kubectl delete -f yamls/ns-dev.yaml namespace "dev" deleted
2. Pod
Pod 是kubernetes集群进行管理的最小单元,程序要运行必须部署在container中,而container必须存在于Pod中。
Pod可以认为是container的封装,一个Pod中可以存在一个或多个container。如下图所示,默认会有一个根容器(也就是这里的Pause),此容器不会在 get pods 时显示给用户。
Kubernetes在集群启动后,集群中的各个组件也都是以Pod方式运行的。可以通过以下命令查看:
$ kubectl get pods -n kube-system NAME READY STATUS RESTARTS AGE aws-node-jtzb7 1/1 Running 0 22h coredns-74c8b6b7dd-7nhz8 1/1 Running 0 23h coredns-74c8b6b7dd-v6ztk 1/1 Running 0 23h kube-proxy-lhd84 1/1 Running 0 22h
此结果为 aws eks 集群的结果。在自建的eks集群中,一般还会有 etcd-master、kube-apiserver-master、kube-controller-manager-master、kube-scheduler-master 等 Pods。但是在 aws eks 中,客户端并无法显示这些pods。
另外的aws-node-jtzb7 与kube-proxy-lhd84均对应当前集群中的1个节点(当前集群仅有1个节点)。
Pod 操作
在创建并运行一个pod时,kubernetes没有提供单独运行Pod的命令,都是通过Pod控制器来实现的:
# 命令格式:kubectl run (pod控制器名称) [参数] # --image 指定Pod 镜像 # --port 指定服务暴露的端口 # --namespace 指定namespace $ kubectl run nginx --image=nginx:1.17.1 --port=80 --namespace dev pod/nginx created $ kubectl get pods -o wide -n dev NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx 1/1 Running 0 2m51s 10.0.1.84 ip-10-0-1-217.cn-north-1.compute.internal <none> <none> => 这个 ip 是Pod 的ip,并非节点 ip # 查看更详细内容 kubectl describe pod nginx -n dev
如何访问到此nginx 服务?
首先在 kubectl get pods -o wide -n dev 的结果中,可以看到 pod 的ip 为 10.0.1.84。结合我们指定暴露的端口为 80,在访问时通过curl 10.0.1.84:80 访问即可。
创建pod与创建deployment的不同:
- kubectl run 一个pod后,一般会显示 pod/nginx created。此时创建的是单个pod,可以直接通过delete pod xxx 进行删除
- kubectl create deploy nginx --image=nginx:1.17.1 -n dev 会创建一个deployment,一般会显示deployment.apps/nginx created。此时创建的是一个deployment,直接删除一个pod 的话,会立即自动再创建一个pod。需要通过 $ kubectl delete deployment nginx -n dev 删除一个deployment,返回的结果是:deployment.apps "nginx" deleted
基于配置文件进行操作
创建一个pod-nginx.yaml,内容为:
apiVersion: v1 kind: Pod metadata: name: nginx namespace: dev spec: containers: - image: nginx:1.17.1 imagePullPolicy: IfNotPresent name: pod ports: - name: nginx-port containerPort: 80 protocol: TCP
创建:
$ kubectl create -f yamls/pod-nginx.yaml
pod/nginx created
删除:
$ kubectl delete -f yamls/pod-nginx.yaml
pod "nginx" deleted
3. Label
Label 是kubernetes系统中的一个重要概念。它的作用就是在资源上添加标识,用来对它们进行区分和选择。
Label的特点:
- 一个Label会以key/value键值对的形式附加到各种对象上,如Node、Pod、Service等
- 一个资源对象可以定义任意数量的Label,同一个Label也可以被添加到任意数量的资源对象上去
- Label 通常在资源对象定义时确定,当然也可以在对象创建后动态添加或删除
可以通过Label实现资源的多维度分组,以灵活、方便地进行资源分配、调度、配置、部署等管理工作。常用的Label如:
• 版本标签:"version":"release", "version":"stable" • 环境标签:"environment":"dev", "environment":"test", "environment":"pro" • 架构标签:"tier":"frontend", "tier":"backend"
在标签定义完毕后,还要考虑标签的选择,这时就要使用到Label Selector,即:
- Label 用于给某个资源对象定义标识
- Label Selector 用于查询和筛选拥有某些标签的资源对象
当前有2种Label Selector:
- 基于等式的Label Selector:name = slave
- 选择所有包含 Label 中 key=”name” 且 value=”slave” 的对象;env != production:选择所有包含Label中key = “env” 且value !=”production” 的对象
- 基于集合的Label Selector:
- name in (master, slave):选择所有包含Label中的key=”name” 且value=”master” 或 “slave” 的对象
-
name not in (frontend):选择所有包含Label中的key=”name” 且value不等于”frontend” 的对象
标签的选择条件可以使用多个,此时将多个Label Selector 进行组合,使用逗号“,” 进行分隔即可。例如:
name=slave, env!=production
name not in (frontend), env!=production
Label操作
命令方式:
# 为pod资源打标签 $ kubectl label pod nginx version=1.0 -n dev pod/nginx labeled $ kubectl label pod nginx -n dev tier=back pod/nginx labeled # 查看标签 $ kubectl get pod -n dev --show-labels NAME READY STATUS RESTARTS AGE LABELS nginx 1/1 Running 0 6m2s tier=back,version=1.0 # 为pod 资源更新标签 $ kubectl label pod nginx1 version=2.0 -n dev --overwrite pod/nginx1 labeled $ kubectl get pods -n dev --show-labels NAME READY STATUS RESTARTS AGE LABELS nginx 1/1 Running 0 15m tier=back,version=1.0 nginx1 1/1 Running 0 89s run=nginx1,version=2.0 # 标签选择 $ kubectl get pods -l "version=2.0" -n dev --show-labels NAME READY STATUS RESTARTS AGE LABELS nginx1 1/1 Running 0 2m run=nginx1,version=2.0 # 删除标签 $ kubectl label pod nginx -n dev tier- pod/nginx labeled $ kubectl get pods -n dev --show-labels NAME READY STATUS RESTARTS AGE LABELS nginx 1/1 Running 0 18m version=1.0 nginx1 1/1 Running 0 4m10s run=nginx1,version=2.0
以配置方式:
在yaml文件中加上label字段:
$ cat yamls/pod-nginx.yaml apiVersion: v1 kind: Pod metadata: name: nginx namespace: dev labels: version: "3.0" tier: "production" spec: containers: - image: nginx:1.17.1 imagePullPolicy: IfNotPresent name: pod ports: - name: nginx-port containerPort: 80 protocol: TCP
4. Deployment
在kubernetes 中,Pod是最小的控制单元,但是kubernetes很少直接控制Pod,一般都是通过Pod控制器来完成。Pod控制器用于pod的管理,确保pod资源符合预期的状态,当pod资源出现故障时,会尝试进行重启或重建pod。
在kubernetes中Pod控制器的种类有很多,下面主要介绍其中一种:Deployment。
Deployment操作
命令方式:
# 创建 $ kubectl create deploy nginx-dep --image=nginx:1.17.1 -n dev deployment.apps/nginx-dep created # 查看 $ kubectl get deploy -n dev -o wide NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR nginx-dep 1/1 1 1 37s nginx nginx:1.17.1 app=nginx-dep $ kubectl get pods -n dev --show-labels NAME READY STATUS RESTARTS AGE LABELS nginx-dep-74c95fbff9-lsngl 1/1 Running 0 19s app=nginx-dep,pod-template-hash=74c95fbff9 => 可以看到 deployment 有个SELECTOR 的标签选择器,选择的标签即为启动的pod自动打上的名称标签 # 删除 $ kubectl delete deploy nginx-dep -n dev deployment.apps "nginx-dep" deleted
配置文件方式:
$ cat yamls/deploy-nginx.yaml apiVersion: apps/v1 kind: Deployment metadata: name: nginx-dep namespace: dev spec: replicas: 3 selector: matchLabels: run: nginx template: metadata: labels: run: nginx spec: containers: - image: nginx:1.17.1 name: nginx ports: - containerPort: 80 protocol: TCP selector 就是label选择器,pod哪里的label给予的是run:nginx
$ kubectl apply -f yamls/deploy-nginx.yaml deployment.apps/nginx-dep created $ kubectl get deploy -n dev NAME READY UP-TO-DATE AVAILABLE AGE nginx-dep 3/3 3 3 103s $ kubectl get pods -n dev NAME READY STATUS RESTARTS AGE nginx-dep-755c49cf64-462g5 1/1 Running 0 2m21s nginx-dep-755c49cf64-s74rx 1/1 Running 0 2m21s nginx-dep-755c49cf64-sgc88 1/1 Running 0 2m21s $ kubectl delete -f yamls/deploy-nginx.yaml
5. Service
现在我们可以通过deployment创建一组Pods,用于提供高可用服务。
但是,虽然每个Pod都会被分配一个单独的Pod IP,仍会存在以下2个问题:
- Pod IP会随着Pod的重建产生变化
- Pod IP仅是集群内可见的虚拟IP,外部无法访问
这样对于访问服务带来了难度。因此,kubernetes设计了Service来解决此问题。
Service可以看作是一组同类Pod对外的访问接口。借助Service,应用可以很方便地实现服务发现和负载均衡。
如下图所示:
一个请求在访问Service时,Service会通过标签选择器选择需要访问的Pod,然后将请求转发到对应的Pod中,其中也涉及负载均衡算法。Service在其整个生命周期中,IP地址都是不变的。
Service操作
创建集群内部可访问的Service
# 暴露Service $ kubectl expose deploy nginx-dep --name=svc-nginx1 --type=ClusterIP --port=80 --target-port=80 -n dev service/svc-nginx1 exposed 此时暴露的是deployment,而不是直接1个pod。--port 指定的是 service 80 端口,转发到pod上的 80 端口(--terget-port=80) # 查看Service $ kubectl get svc -n dev NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE svc-nginx1 ClusterIP 172.20.246.209 <none> 80/TCP 65s # 由于指定的是ClusterIP,所以仅有集群内的节点能访问到此服务 # 通过 eks node 访问此地址: $ curl 172.20.246.209 … <p><em>Thank you for using nginx.</em></p> … # 删除svc $ kubectl delete svc svc-nginx2 -n dev service "svc-nginx2" deleted
创建集群外部也能访问Service
# 若是需要外部也能访问,则需要修改type为NodePort $ kubectl expose deploy nginx-dep --name=svc-nginx2 --type=NodePort --port=80 --target-port=80 -n dev service/svc-nginx2 exposed $ kubectl get svc -n dev -o wide NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR svc-nginx1 ClusterIP 172.20.246.209 <none> 80/TCP 8m13s run=nginx svc-nginx2 NodePort 172.20.140.200 <none> 80:31890/TCP 18s run=nginx
$ kubectl apply -f yamls/svc-nginx.yaml service/svc-nginx created $ kubectl delete -f yamls/svc-nginx.yaml service "svc-nginx" deleted