关于 Kubernetes 系列其他文章的传送门
-
《 初识 k8s,新时代的宠儿 》 您当前所在位置

一、Kubernetes 中的一些重要的概念¶
3 个控制平面¶
- API Server:监听在 Master 中 node 网络 的
6443套接字上,提供 https 接入;早期还提供8080以供 http 使用,后来被取消;- 用户认证:采用双向认证,客户端也要提供证书。并且是由信任的 CA 颁发的,在部署 k8s 时,在
/etc/kubernetes/pki目录下自动创建了 CA 的相关证书。其中ca.crt就是 CA 的私钥。
- 用户认证:采用双向认证,客户端也要提供证书。并且是由信任的 CA 颁发的,在部署 k8s 时,在
- Scheduler:负责将创建的 Pod 调度到某个节点运行;
- Controller:调度完成后,由 Controller 确保有精确数量的 Pod 资源在正常运行;
Node 节点的重要功能¶
- 运行 Pod;
- 由
kube-proxy在 Node 节点上的 Ipvs 或 iptables 中创建 Services 的规则;
k8s 中重要的组件¶
最重要的一些基础组件,Pod、Pod Controller、Service 之间的关系:
- 由 Pod Controller 创建 Pod:
- 首先明确:
Deployment是一种类型。向一个Deployment类型的属性赋值创建出一个具体的 Pod Controller,再由 Controller 创建出 Pod。 Service也是一种类型,通常需要通过赋值的方式来实例化。假设为Service的属性赋值,创建出一个特定的Service实例叫nginx-svc,这个实例就能关联到 Pod 上,为 Pod 中的 nginx 调度用户请求。
- 首先明确:
k8s 中的资源有两个级别¶
- 集群级别;
- 名称空间级别;
二、一些基础命令的使用方法¶
客户端命令¶
kubectl 是客户端,它连接到 API Server 来控制 k8s 集群:
get nodes:显示主机信息;属于集群级别的资源;get ns:显示名称空间的信息;- k8s 部署后默认会创建 3 个名称空间:
default:默认用于运行没指定名称空间的 Pod,kube-public:用于运行公共的 Pod,任何人都可以访问;kube-system:专门用于运行系统级的 Pod;
- k8s 部署后默认会创建 3 个名称空间:
get pods:显示 Pod 的相关信息;-n显示指定名称空间中的 Pod;-o wide:类似ls,显示长格式信息;-w:代表watch,动态显示 Pod 的状态。
比如下面这样,就是查看在 kube-system 的名称空间内,有哪些 deploy 类型的控制器。
1 | kubectl get deploy -n kube-system |
查询资源¶
先指定资源的类型,再指定要查询的名称,以 ns 资源类型为例:
kubectl describe ns/default:显示指定名称空间的状态信息;kubectl get ns:查询所有名称空间的信息;kubectl get ns/default:查询指定名称空间的信息;kubectl get ns/default -o [ yaml | json ]:查询指定名称空间的详细信息,并以指定格式显示。
创建资源¶
kubectl api-resources:查看可用的资源类型;全称和简格式都可以使用
使用 kubectl create 可以创建一个新的资源,要先指定资源的类型,再指定名称;
常用的资源类型有以下:
- clusterrole
- clusterrolebinding
- configmap
- cronjob
- deployment
- job
- namespace
- poddisruptionbudget
- priorityclass
- quota
- role
- rolebinding
- secret
- service
- serviceaccount
创建和删除名称空间¶
创建
1 | kubectl create namespace develop-1 |
删除 ns 同理,有两种格式可以使用:
kubectl delete namespace dev-1:一次只能删除一个;kubectl delete namespace/dev-1 namespace/test-1 namespace/run-1:一次能删除多个;
注意:删除名称空间会一并删除内部的所有资源,很危险;
创建 Pod 控制器¶
创建一个名为 ngx-dep 的控制器,使用指定的 nginx 镜像:
1 | kubectl create deploy ngx-dep --image=nginx:1.14-alpine |
使用 kubectl get all 查看查看 default 名称空间下的所有资源。
如果把 Pod 删除,deploy 控制器会自动再创建一个 Pod 出来。
创建 Service¶
创建一个 ClusterIP 类型的 Service 并关联至 Pod,同时指定映射 80 端口;
并且可以使用 --clusterip 指定 IP,如不指定则随机;
1 | kubectl create service clusterip ngx-dep --tcp=80:80 |
注意:定义 Service 的名字时,要和后端的 Pod 控制器名称一致,才会自动关联映射:
使用 kubectl describe service/ngx-dep 可以查询 service IP 和 pod IP 的映射关系。
如果 Pod 被重建后 IP 发生了变化,那么这个 service 就会自动和新的 Pod IP 绑定。
思考:IP 变化后,如何访问?¶
当 service 自己被重建后,IP 会发生变化,那么客户端该如何访问呢?
在 k8s 内部有一个 DNS,在 DNS 中记录着 “域名 -> service IP” 的对应关系,当 service 被重建,IP 发生变化时,这个记录中的对应关系也会跟着变化,那么客户端只要使用这个域名访问就可以了。客户端把 DNS 指向 k8s 内部的 DNS 地址,即可解析域名。
查看 DNS 地址的方法:
- 使用
kubectl get svc -n kube-system,找到 DNS 的 Service,名字为kube-dns,就可以看到 IP 地址了。域名的格式是:
ngx-dep.default.svc.cluster.local.
- 含义是:
service名称.service所在的名称空间.资源的类型(固定后缀).当前k8s所在的域名.,注意最后有.。在部署 k8s 时使用
--service-dns-domain string可以指定集群域名,默认使用cluster.local。
Pod 扩、缩容¶
扩容¶
先创建一个 Pod 和对应的 svc:
1 | kubectl create deploy myapp --image=ikubernetes/myapp:v1 |
将刚才创建的 myapp 扩容为 3 个,并指定控制器类型为 deployment:
1 | kubectl scale --replicas=3 deployment myapp |
查看结果:
1 | # kubectl get pods -o wide |
并且 svc 中也添加了对应的映射关系:
1 | # kubectl describe svc/myapp |
接下来通过域名访问 svc 对应的域名时,会有负载均衡的效果,默认的调度方式是随机:
1 | # curl myapp.default.svc.cluster.local/hostname.html |
缩容¶
缩容的方法就是把扩容时指定的数量减小即可,控制器会自动删除多余的,做到精准控制 Pod 的数量:
1 | kubectl scale --replicas=3 deployment myapp |
三、API Server¶
API 相关的基础概念¶
API 接口中的资源被分成多个逻辑组合:
- 通常情况下,相关的类型会被存放在同一个组合内,被称为 API Group;
- 使用
kubectl api-versions可以查看有多少群组; - 其中
V1是核心存储,所有核心的组件都在这个组中;
- 使用
- 每个组中的资源可以独立演进,实现分而治之;
- 每个组还可以多版本并存;
绝大部分资源都遵循相同的 资源对象配置格式,有 5 个一级字段:
kind:用于标识对象所属的资源类型;apiVersion:指定使用哪个 API 群组以及版本;metadata:属于嵌套字段,保存着资源的元数据,包括名称、所属的名称空间、标签、创建时间等等;spec:定义资源的规范,用户期望达到的状态;status:资源的当前状态,用户不能手动定义,由 k8s 自行维护。
和解循环(Reconciliation Loop)¶
Controller(控制器)会周期性的检查 status 是否符合 spec 中的状态,如不符合将运行合适的操作,使 status 中的状态无限接近 spec 的状态。
资源对象的管理方式¶
使用 kubectl 管理资源,命令可分为三类:
1. 陈述式命令(Imperative Commands)¶
告诉对方要做什么,至于怎么做不用管。
- 像
delete、get之类的命令;
2. 陈述式对象配置(Imperative Object Configuration)¶
要按照指定的配置文件中定义的具体细节创建资源。
- 使用
kubectl create -f FILE.yaml指定一个 yaml 格式的资源配置文件;- 相同名字的资源只能创建一次,再次创建前需要先删除;
- 删除可使用
kubectl delete -f FILE.yaml即可删除;
3. 声明式对象配置(Declarative Object Configuration)¶
要按照指定的配置文件中定义的具体细节创建资源。建议使用。
- 使用
kubectl apply -f FILE.yaml指定一个 yaml 格式的资源配置文件。
所不同的是:
- 相同名字的资源可以反复创建,还可以指定一个目录,将目录下所有配置文件的资源全部创建。
清单文件¶
清单文件可以根据 官网中 API 的参考说明 自己编写,也可以从现有的资源直接导出为模板。
比如将 coredns 的 Pod 资源配置文件导出的方法:
1 | `~]# kubectl get pod -n kube-system coredns-5644d7b6d9-2khq8 -o yaml --export > /root/pod-demo.yaml` |
-o yaml:指定显示为 yaml 格式;--export:导出为模板使用;
API 查询工具 explain¶
k8s 内置了一个工具 explain,可以查询指定资源类型的配置参数,语法为:
1 | kubectl explain <type>.<fieldName>[.<fieldName>] |
- 比如想查看 Pods 可用参数,使用
kubectl explain pods即可列出; - 如果再想查看 Pods 下的
kind字段中还有哪些参数可用,则使用.递归,比如kubectl explain pods.kind。
四、手动编写资源配置清单¶
关于拉取镜像的参数¶
imagePullPolicy:定义默认拉取镜像的方式,有三个可用值:Always:代表无论本地是否有镜像,都去网上的仓库拉取;Never:代表如果本地没有镜像,就不启动;IfNotPresent:代表如果目标节点有镜像,就使用,否则就拉取;
而针对不同的镜像,标签不同,默认值也不一样:
- 如果镜像的标签是 latest,默认值则为
always,因为本地的 latest 版本不一定是互联网上最新的; - 否则默认值就为
ifnotpresent。
创建自主式 Pod¶
自主式的 Pod 不归 Pod 控制器管理,生产环境不建议这么做,仅为了理解 Pod 而做演示。
1 | ~]# vim /root/pod-nginx.yaml |
而后创建自主式 Pod:
1 | kubectl apply -f /root/pod-nginx.yaml |
在一个 Pod 内启动两个容器的方式¶
1 | ~]# vim /root/pod-2.yaml |
而后创建 Pod:
1 | kubectl apply -f /root/pod-2.yaml |
进入容器的交互式接口¶
一个 Pod 内有两个容器时,使用 -c 来指定容器。如只有一个容器,-c 可省略。
1 | kubectl exec pod-2 -c bbox -n default -it -- /bin/sh |
思考:80 端口从何而来?¶
可以看到 bbox 的容器内监听了
80端口,但是 bbox 内并没有启动 web 服务,那么80端口从何而来呢?因为与 bbox 在同一个 Pod 内的另一个容器 nginx 监听了
80端口,而同一个 Pod 内的所有容器是共享同一个网络名称空间的。
查看 Pod 中容器的日志¶
1 | 使用 -c 来指定容器,如只有一个容器 -c 可省略 |
五、对外暴露 Pod 端口¶
在 k8s 中,如果需要将端口暴露给集群外的客户端访问,有三种方式:
- hostNetwork:共享所在物理机的网络名称空间;
- NodePort:每个物理节点中的 iptables/IPVS 都有规则;
- hostPort(DNAT)
NodePort¶
先创建一个 NodePort 类型的 Service,名字和后端 Pod 一致:
1 | kubectl create service nodeport myapp --tcp=80:80 |
会发现在这个 svc 的端口中,映射了一个 31114 的随机端口。
1 | kubectl get svc |
这是物理机上的端口,可以直接通过任意一台物理机的 IP 加 31114 端口进行访问,因为创建 NodePort 类型的 svc 后,每个节点上的 kube-proxy 程序会在所有物理机节点中的 iptables/IPVS 中添加相应的规则。
hostNetwork¶
Pod 创建后会被调度到某个物理机,下面这种方法可以让 Pod 共享所在物理机的网络名称空间:
1 | ~]# vim /root/pod-host.yaml |
而后创建 Pod:
1 | kubectl apply -f /root/pod-host.yaml |
查看此 Pod 使用的地址,已经是宿主机的 IP 地址了:
1 | kubectl get pods -o wide |
但是这种方法并不常用,因为如果很多 Pod 都使用 80 端口的话,当他们被调度到同一台物理机时就会发生冲突了,而下面的方法可以改善这个问题。
DNAT 容器端口¶
把容器的端口添加一个别名,使其能被引用,而后在物理机端口中引用它,实现 DNAT。
即:hostPort -> DNAT -> containerPort
1 | ~]# vim /root/pod-dnat.yaml |
而后创建 Pod:
1 | kubectl apply -f /root/pod-dnat.yaml |
查看刚创建的 Pod 的地址,使用的是 Pod 网络中的 IP。Pod 被调度到 node2 节点,于是访问 node2 节点的 IP:8080 就可以访问了。
1 | kubectl get pods -o wide |