kubernetes入门
一.导言
随着容器技术的发展,软件界对容器管理的需求越来越迫切,于是出现了一些kubernetes(即k8s),docker swarm 等容器管理软件。同时k8s等服务编排软件也让微服务变得可行,快速扩容缩容,自动处理网络配置等特性也让k8s如火如荼。
k8s能做什么?
- 服务发现和负载均衡,使用dns或者ip对外暴露容器服务,并提供负载均衡
- 存储管理,多种存储选择
- 拟态扩容缩容,根据需求扩容,缩容,并且k8s会尽力达到desired state
- 自动装箱,比如配置每个容器能使用的CPU和RAM资源,k8s将容器分配到合适的节点以最大化利用系统资源
- 自动处理故障,当容器失效时,能快速处理,并且不会对客户端有影响
- 配置和秘钥管理
二.k8s架构及相关概念
control plane:控制台
kube-apiserver: k8s的核心api服务,一般需要做横向扩展
etcd: 提供一致性和高可用的的键值存储,k8s用来存储集群数据。etcd是一款用go语言编写的分布式kv存储,基于raft算法,能提供更稳定的高负载稳定读写能力。
kube-scheduler: 为未分配节点的pod寻找合适的节点
kube-controller-manager: 包括以下controller
- node controller: 监视节点下线
- job-controller: 监视Job 运行状况
- EndpointSlice controller: 即端点列表控制器,为Service 和 pod 提供连接
cloud-controller-manager: 云服务控制管理
node:节点,对应物理机或者虚拟机
kubelet: 运行在节点中的agent,确保容器运行在pod中
kube-proxy: 运行在节点中的网络代理,为Servcie提供支持
pod: k8s 抽象出来的的管理单元,包括一个或者多个容器,共享存储,网络,端口等资源
volume: 存储单元抽象
container:容器,比如docker
Deployment:部署,描述部署的容器,复制等信息,一个典型的Deployment如下
apiVersion: apps/v1 (版本)
kind: Deployment (对象类型)
metadata: (元数据)
name: nginx-deployment (name, UIDs)
spec: (目标状态)
selector:
matchLabels:
app: nginx
replicas: 2 # tells deployment to run 2 pods matching the template
template:
metadata:
labels: (labels and selector)
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
Service:基于pod创建对外或者对内网络服务
三.构建无状态服务
无状态服务:服务不依赖自身的状态,实例的状态数据可以维护在内存中。
构建步骤如下:
0.笔者这里使用minikube进行测试,先启动minikube
minikube start
minikube dashboard # 启动后台管理界面
1.执行部署
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/name: load-balancer-example
name: hello-world
spec:
replicas: 5
selector:
matchLabels:
app.kubernetes.io/name: load-balancer-example
template:
metadata:
labels:
app.kubernetes.io/name: load-balancer-example
spec:
containers:
- image: gcr.io/google-samples/node-hello:1.0
name: hello-world
ports:
- containerPort: 8080
kubectl apply -f https://k8s.io/examples/service/load-balancer-example.yaml
2.查看部署信息
kubectl get deployments hello-world
kubectl describe deployments hello-world
NAME READY UP-TO-DATE AVAILABLE AGE
hello-world 5/5 5 5 12m
3.查看副本集
这里我们创建了五个副本
kubectl get replicasets
kubectl describe replicasets
NAME DESIRED CURRENT READY AGE
hello-world-644f58f5f4 5 5 5 12m
4.创建Service暴露部署
kubectl expose deployment hello-world --type=LoadBalancer --name=my-service # LoadBalancer表示使用负载均衡的方式
5.查看Service
kubectl get services my-service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-service LoadBalancer 10.102.184.247 <pending> 8080:31755/TCP 3s
6.查看Service详细信息
kubectl describe services my-service
Name: my-service
Namespace: default
Labels: app.kubernetes.io/name=load-balancer-example
Annotations: <none>
Selector: app.kubernetes.io/name=load-balancer-example
Type: LoadBalancer
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.102.184.247
IPs: 10.102.184.247
Port: <unset> 8080/TCP
TargetPort: 8080/TCP
NodePort: <unset> 31755/TCP
Endpoints: 10.244.0.87:8080,10.244.0.88:8080,10.244.0.89:8080 + 2 more... # 端点
Session Affinity: None
External Traffic Policy: Cluster
Events: <none
7.查看pod对应的端点
kubectl get pods --output=wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
hello-world-644f58f5f4-2slc4 1/1 Running 0 8m46s 10.244.0.91 minikube <none> <none>
hello-world-644f58f5f4-jjf6w 1/1 Running 0 8m46s 10.244.0.88 minikube <none> <none>
hello-world-644f58f5f4-mzd5x 1/1 Running 0 8m46s 10.244.0.90 minikube <none> <none>
hello-world-644f58f5f4-t6cmj 1/1 Running 0 8m46s 10.244.0.89 minikube <none> <none>
hello-world-644f58f5f4-xlvtr 1/1 Running 0 8m46s 10.244.0.87 minikube <none> <none>
8.访问服务
使用 curl http://<external-ip>:<port> 进行访问。
<external-ip> 这里指代LoadBalancer Ingress地址,许多厂商开发了各种网关和k8s集成。
<port> 指代Service暴露的端口。
如果是minikube,直接启动即可
➜ k8s minikube service my-service
|-----------|------------|-------------|---------------------------|
| NAMESPACE | NAME | TARGET PORT | URL |
|-----------|------------|-------------|---------------------------|
| default | my-service | 8080 | http://192.168.49.2:31755 |
|-----------|------------|-------------|---------------------------|
🏃 Starting tunnel for service my-service.
|-----------|------------|-------------|------------------------|
| NAMESPACE | NAME | TARGET PORT | URL |
|-----------|------------|-------------|------------------------|
| default | my-service | | http://127.0.0.1:53820 |
|-----------|------------|-------------|------------------------|
🎉 正通过默认浏览器打开服务 default/my-service...
❗ Because you are using a Docker driver on darwin, the terminal needs to be open to run it.
三.构建有状态服务
有状态服务 · 服务本身依赖或者存在局部的状态数据,这些数据需要自身持久化或者可以通过其他节点恢复。
1.添加自定义配置文件,存储mysql密码
cat <<EOF >./kustomization.yaml
secretGenerator:
- name: mysql-pass
literals:
- password=YOUR_PASSWORD
EOF
2.编写部署mysql 和 WordPress文件
mysql部署文件 application/wordpress/mysql-deployment.yaml:
apiVersion: v1
kind: Service # 部署服务
metadata:
name: wordpress-mysql
labels:
app: wordpress
spec:
ports:
- port: 3306
selector:
app: wordpress
tier: mysql
clusterIP: None
---
apiVersion: v1
kind: PersistentVolumeClaim # 指定持久化存储
metadata:
name: mysql-pv-claim
labels:
app: wordpress
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
---
apiVersion: apps/v1
kind: Deployment # mysql部署
metadata:
name: wordpress-mysql
labels:
app: wordpress
spec:
selector:
matchLabels:
app: wordpress
tier: mysql
strategy:
type: Recreate
template:
metadata:
labels:
app: wordpress
tier: mysql
spec:
containers:
- image: mysql:5.6
name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-pass # 使用之前定义的秘钥
key: password
ports:
- containerPort: 3306
name: mysql
volumeMounts:
- name: mysql-persistent-storage
mountPath: /var/lib/mysql # 将该路径的存储映射到mysql-pv-claim
volumes:
- name: mysql-persistent-storage
persistentVolumeClaim:
claimName: mysql-pv-claim
WordPress 部署文件:application/wordpress/wordpress-deployment.yaml
apiVersion: v1
kind: Service # 暴露服务
metadata:
name: wordpress
labels:
app: wordpress
spec:
ports:
- port: 80
selector:
app: wordpress
tier: frontend
type: LoadBalancer
---
apiVersion: v1
kind: PersistentVolumeClaim # 指定持久化存储
metadata:
name: wp-pv-claim
labels:
app: wordpress
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress
labels:
app: wordpress
spec:
selector:
matchLabels:
app: wordpress
tier: frontend
strategy:
type: Recreate
template:
metadata:
labels:
app: wordpress
tier: frontend
spec:
containers:
- image: wordpress:4.8-apache
name: wordpress
env:
- name: WORDPRESS_DB_HOST
value: wordpress-mysql
- name: WORDPRESS_DB_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-pass
key: password
ports:
- containerPort: 80
name: wordpress
volumeMounts:
- name: wordpress-persistent-storage
mountPath: /var/www/html # 存储路径映射
volumes:
- name: wordpress-persistent-storage
persistentVolumeClaim:
claimName: wp-pv-claim
将以上文件写入到kustomization.yaml中
cat <<EOF >>./kustomization.yaml
resources:
- mysql-deployment.yaml
- wordpress-deployment.yaml
EOF
3.执行部署
kubectl apply -k ./ #确保上述文件在当前目录下
查看秘钥:
➜ k8s kubectl get secrets
NAME TYPE DATA AGE
mysql-pass-kkcc2b926b Opaque 1 3d22h
查看PersistentVolume:
➜ k8s kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
mysql-pv-claim Bound pvc-456c2492-32bd-4d15-9753-c3ad1034c38f 20Gi RWO standard 3d22h
wp-pv-claim Bound pvc-78d63fcd-9c75-4320-97d6-4498d2915707 20Gi RWO standard 3d22h
查看pod:
➜ k8s kubectl get pods
NAME READY STATUS RESTARTS AGE
wordpress-7fdfc976b9-4tx6d 1/1 Running 0 16s
wordpress-mysql-6987d65455-f44dz 1/1 Running 0 16s
查看Service:
➜ k8s kubectl get services wordpress
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
wordpress LoadBalancer 10.101.95.45 <pending> 80:31798/TCP 3d22h
运行服务,访问 http://127.0.0.1:52503/ 即可看到服务地址
➜ k8s minikube service wordpress --url
http://127.0.0.1:52503
❗ Because you are using a Docker driver on darwin, the terminal needs to be open to run it.
四.网络模型
k8s给集群里面的每个pod分配集群内 IP地址,这个ip仅仅限制在集群内部使用。
- pod之间可以互相访问,不依赖NAT(Network Address Translation)
- 节点上的agent(kubelet)可以和其他节点上的pod互相访问
"IP-per-pod" model:同一个pod里面的容器共享网络命名空间,即共享ip地址,mac地址等等。这意味着pod里面的容器可以使用localhost互相访问对方的端口,同时要求容器内的端口不能互相冲突。
- pod里面的容器使用loopback 互相访问
- pod之间通过cluster-wide IP 互相访问
- 可以使用Service暴露服务,方便从集群外部访问。许多厂商开发了各类网关,以支持http 应用,网站,和APIs
五.最佳实践
- 所有配置文件,比如Deployment, Service 应该进行版本控制,推送到git仓库
- 先创建Service,然后再创建Deployment,这样pod就能获得Service的相关信息
- 使用DNS server插件
- 不要为pod指定地址端口
- 使用语义化的标签来进行管理应用或者部署,比如{ app.kubernetes.io/name: MyApp, tier: frontend, phase: test, deployment: v3 }
六.CRI 之 docker engine
1.容器发展史
2.docker 架构和底层技术
docker 使用go语言编写,使用namespaces 来隔离workspace (container)。当我们创建一个container,docker创建一系列的namespace来进行隔离。
docker 使用cgroup来进行资源控制。
3.docker 中的一些关键概念
- 每个container只包含一个进程
- 可以使用docker compose,组合多个container进行管理
- docker提供两种持久化方式,volumes(使用卷的方式), bind mounts(挂载)
- image是分层的,并且可以缓存
- 使用Multi-stage builds,只保留最后一阶段的输出
4.docker最佳实践
image:
-
- 选择合适的base image
- 使用Multi-stage builds,可以让image变得更小
- 在共享组件的基础上构建image
- 对image打标签
- 在正式环境使用volumes存储,在开发环境使用bind mounts存储
- 使用CI/CD开发
dockerfile:
-
- 创建无状态的container
- 使用stdin 创建 Dockerfile
- 使用.dockerignore排除文件
- 使用Multi-stage builds
- 不要安装不必要的包
- 解耦应用,每个container只运行一个进程
- 减少layer的数量
七.总结
本文介绍了k8s的核心架构,和重要相关概念,并且演示了两个典型用例。同时介绍了docker的相关知识。
八.参考
https://docs.docker.com/get-started/
https://kubernetes.io/docs/home/