本文主要介绍k8s的核心实战:
- Namespace(命名空间)。
- Pod(是kubernetes中应用的最小单位)。
- Deployment(控制Pod,使Pod拥有多副本,自愈,扩缩容等能力)。
- Service(将一组 Pods 公开为网络服务的抽象方法)。
- Ingress(相当于统一的网关访问入口)。
- PV&PVC(存储抽象)。
- ConfigMap(ConfigMap抽取应用配置,并且可以自动更新)。
- Secret(Secret 对象类型用来保存敏感信息,例如密码、OAuth 令牌和 SSH 密钥。 将这些信息放在 secret 中比放在 Pod 的定义或者 容器镜像 中来说更加安全和灵活。)。
- 命令行
- YML
Namespace 名称空间,用来对集群资源进行隔离划分,默认只隔离资源,不隔离网络
使用命令行的方式创建名称空间:
# 获取所有的名称空间 全称namespace 或者缩写ns都可以 kubectl get ns # 创建一个名称空间 kubectl create ns hello # 删除名称空间 kubectl delete ns hello
使用yml文件创建名称空间:
# 版本 apiVersion: v1 # 类型 kind: Namespace #元数据 metadata: name: hello
创建yml资源文件
# 创建hello.yml资源文件 vim hello.yml #使用kubectl apply命令创建名称空间 kubectl apply -f hello.yml #使用kubectl apply命令删除名称空间 kubectl delete -f hello.yml2.3 Pod
Pod是运行中的一组容器,Pod是Kubernetes中应用的最小单位。
2.3.1 创建Pod#创建Pod kubectl run myk8snginx --image=nginx
# kubectl describe pod 命令查看容器描述 在Events里可以看到容器的运行日志 kubectl describe pod myk8snginx
从日志中可以看到从开始分配到了node02节点,然后开始拉取镜像,拉取成功,开始创建容器,最后启动容器。
所以我们的容器是在node02节点运行的,并且只能在node02节点上才能看到。
master节点:
node01节点:
node02节点:
#删除Pod -n指定名称空间 kubectl delete pod Pod名字2.3.3 使用yml配置文件方式创建Pod
创建yml文件:
apiVersion: v1
kind: Pod
metadata:
labels:
run: mynginx
name: mynginx
# namespace: default
spec:
containers:
- image: nginx
name: mynginx
#使用kubectl apply 命令创建Pod kubectl apply -y pod.yml # 同样也可以使用kubectl delete命令删除 kubectl delete -y pod.yml
查看Pod运行日志:
# 查看Pod运行日志 kubectl logs mynginx2.3.4 使用Dashboard操作
同样可以使用可视化界面进行操作:
执行:进入容器内部。
日志:查看容器运行日志。
删除
#kubectl get查看应用更详细信息 kubectl get pod -owide # 每个PodK8s都会分配一个IP。使用Pod的Id+容器里运行的端口访问 #使用curl命令访问nginx curl 192.168.58.1952.3.6 进入容器
#进入容器 kubectl exec -it pod名称 -- /bin/bash # 修改nginx的首页,进入到/usr/share/nginx/html目录修改index.html文件 cd /usr/share/nginx/html echo "This is K8s Word -- Nginx!" >index.html
注意:这个K8s分配的Ip在任意节点都可以访问。
也可以直接使用Dashboard里进入到容器内部:
apiVersion: v1
kind: Pod
metadata:
labels:
run: myapp
name: myapp
spec:
containers:
- image: nginx
name: nginx
- image: tomcat:8.5.68
name: tomcat
我们直接使用Dashboard创建Pod。
创建完成后使用kubectl get pod命令查看默认命名空间下的应用。发现我们刚刚创建的Pod的两个容器都已经启动成功了。
注意:在Pod内部的两个容器相互访问可以直接使用127.0.0.1。
注意:一个Pod内可以有多个容器,但是端口不能冲突。
Deployment可以控制Pod,使Pod有多副本、自愈、扩缩容等能力。
删除之前的Pod
#可以使用kubectl delete pod 命令 多个Pod用空格隔开 kubectl delete pod myapp-1 myapp-2 -n default2.4.1 自愈能力
# 清除所有Pod,比较下面两个命令有何不同效果? kubectl run mynginx --image=nginx kubectl create deployment mytomcat --image=tomcat:8.5.68 # 自愈能力
删除Pod
#使用 kubectl delete命令删除Pod # 模拟容器宕机、崩溃 kubectl delete pod mytomcat-6f5f895f4f-w6j9c
结论:我们使用Deployment创建的Pod,Pod被删除后会自动重新创建一个新的Pod,使用kubectl run 创建的Pod则可以直接删除。
如果真的需要删除Pod,可以命令
# 查看Deployment kubectl get deploy #删除deployment kubectl delete deploy mytomcat2.4.2 多副本
# my-dep 部署名称 --image=nginx 选择nginx为镜像 --replicas=3指定副本数为3 kubectl create deployment my-dep --image=nginx --replicas=3 kubectl get deploy kubectl get pod -owide
也可以使用yml文件部署:
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: my-dep
name: my-dep
spec:
replicas: 3
selector:
matchLabels:
app: my-dep
template:
metadata:
labels:
app: my-dep
spec:
containers:
- image: nginx
name: nginx
在Dashboard界面创建:
也可以使用表单方式创建:
# 手动扩容 kubectl scale --replicas=5 deployment/my-dep # 缩容 kubectl scale --replicas=2 deployment/my-dep
除了上面的命令,也可以使用kubectl edit命令来编辑yml文件来修改副本数量
#修改 replicas kubectl edit deployment my-dep
保存退出之后就会创建出一个新的Pod。
在Dashboard界面操作就更简单了:
#使用watch命令监视pod状态 watch -n 1 kubectl get pod
目前我们运行了3台Pod:
kubectl get pod -owide查看Pod详细信息:
#在node02节点查看容器 docker ps |grep my-dep-5b7868d854-7gc84 # 停止Docker容器 docker stop fc97f1d58c15
我们发现Pod的已经又重启一次了。
现在将我们的node02节点关机。
可能需要等五六分钟,我们可以看到 在node02节点的Pod已经终结了,正在运行的Pod是在node01上面的三个Pod
也就是新的Pod启动成功后才会把旧的Pod终结。
# 以yml方式查看deploy kubectl get deploy my-dep -oyaml
可以看到使用的镜像是nginx最新版的,name为nginx。
# 滚动更新 deployment/my-dep为deployment nginx为上文中的name 后面为新的镜像 --record记录本次更新 kubectl set image deployment/my-dep nginx=nginx:1.16.1 --record # 查看my-dep的状态 显示deployment "my-dep" successfully rolled out表示部署“my-dep”成功展开 kubectl rollout status deployment/my-dep
kubectl get deploy my-dep -oyaml再次查看deploy的yml文件,发现镜像已经更新了
#历史记录 kubectl rollout history deployment/my-dep #查看某个历史详情 kubectl rollout history deployment/my-dep --revision=2 #回滚(回到上次) kubectl rollout undo deployment/my-dep #回滚(回到指定版本) kubectl rollout undo deployment/my-dep --to-revision=2
可以再次查看镜像
kubectl get deploy/my-dep -oyaml|grep image2.5 其他工作负载
除了Deployment,k8s还有 StatefulSet 、DaemonSet 、Job 等 类型资源。我们都称为 工作负载。
有状态应用使用 StatefulSet 部署,无状态应用使用 Deployment 部署。
将一组 Pods 公开为网络服务的抽象方法。Pod的服务发现与负载均衡。
2.6.1 负载均衡修改三个Pod中的nginx的首页,直接通过Dashboard操作。
cd /usr/share/nginx/html/ echo "1111" > index.html # 在其他节点也同样操作 echo "2222" > index.html echo "3333" > index.html
#暴露Deploy --port映射端口 --target-port目标端口 kubectl expose deployment my-dep --port=8000 --target-port=80 # 等同于 没有--type的 kubectl expose deployment my-dep --port=8000 --target-port=80 --type=ClusterIP #查看service kubectl get service #使用标签检索Pod kubectl get pod -l app=my-dep
集群内使用service的IP:端口号来访问,
同时也可以通过服务名来访问。
注意使用域名的方式只能在Pod容器内部使用。域名规则:deploy名称.名称空间.svc
# 注意使用域名的方式只能在Pod容器内部使用。域名规则:deploy名称.名称空间.svc curl my-dep.default.svc:8000
上面命令也可以通过yml文件来实现:
apiVersion: v1
kind: Service
metadata:
labels:
app: my-dep
name: my-dep
spec:
selector:
app: my-dep
ports:
- port: 8000
protocol: TCP
targetPort: 80
2.6.2 服务发现
当我们使用之前的扩缩容的命令修改Pod的数量后,我们在访问Service服务后不会再访问到已经下线的Pod。
如果我们重新吧副本数扩容为3个。
我们使用 kubectl delete svc my-dep命令将之前创建的service删除。
# ClusterIP 在集群内部访问 kubectl expose deployment my-dep --port=8000 --target-port=80 --type=ClusterIP # NodePort 可以使用公网访问,可以在集群内访问 NodePort范围在 30000-32767 之间 kubectl expose deployment my-dep --port=8000 --target-port=80 --type=NodePort
可以看到NodePort又暴露了一个端口31808
因为官方规定了NodePort范围在 30000-32767 之间,所以我们为了方便直接开放30000-32767的安全组。
我们使用任意节点的公网Ip+31808端口就可以在浏览器进行公网访问。
http://47.102.211.162:31808/ http://139.224.194.116:31808/ http://106.15.52.118:31808/
但是我们通过10.96.84.154:8000也是可以在集群内部访问的:
同样在Pod内部使用域名方式也是可以访问的。
Ingress是Service的统一网关入口。
官网地址:https://kubernetes.github.io/ingress-nginx/
Ingress默认k8s是没有的,需要我们手动安装:
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.47.0/deploy/static/provider/baremetal/deploy.yaml #修改镜像 vi deploy.yaml #将image的值改为如下值: registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images/ingress-nginx-controller:v0.46.0 # kubectl apply -f deploy.yaml kubectl apply -f deploy.yaml # 检查安装的结果 kubectl get pod,svc -n ingress-nginx # 最后别忘记把svc暴露的端口要放行
应用如下yaml,准备好测试环境:
部署hello-server和nginx-demo 的Deployment,两个副本数量,并且创建Service。
可以使用命令行也可以是使用可视化界面进行操作
vi test.yml kubectl apply -f test.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-server
spec:
replicas: 2
selector:
matchLabels:
app: hello-server
template:
metadata:
labels:
app: hello-server
spec:
containers:
- name: hello-server
image: registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images/hello-server
ports:
- containerPort: 9000
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-demo
name: nginx-demo
spec:
replicas: 2
selector:
matchLabels:
app: nginx-demo
template:
metadata:
labels:
app: nginx-demo
spec:
containers:
- image: nginx
name: nginx
---
apiVersion: v1
kind: Service
metadata:
labels:
app: nginx-demo
name: nginx-demo
spec:
selector:
app: nginx-demo
ports:
- port: 8000
protocol: TCP
targetPort: 80
---
apiVersion: v1
kind: Service
metadata:
labels:
app: hello-server
name: hello-server
spec:
selector:
app: hello-server
ports:
- port: 8000
protocol: TCP
targetPort: 9000
现在开始配置Ingress转发规则:
即 使用hello.server.com:请求转发给hello-server服务处理
把nginx.demo.com的请求转发给nginx-demp服务处理。
需要配置hosts文件:
47.102.211.162 hello.server.com #K8s Ingress hello-server服务 47.102.211.162 nginx.demo.com #K8s Ingress nginx-demo服务
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-host-bar
spec:
ingressClassName: nginx
rules:
- host: "hello.server.com"
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: hello-server
port:
number: 8000
- host: "nginx.demo.com"
http:
paths:
- pathType: Prefix
path: "/" # 把请求会转给下面的服务,下面的服务一定要能处理这个路径,不能处理就是404
backend:
service:
name: nginx-demo ## java,比如使用路径重写,去掉前缀nginx
port:
number: 8000
也可以使用命令行来查看配置的ingress规则:kubectl get ingress。
浏览器测试:
访问:http://hello.server.com:31567/返回Hello World!;
访问:http://nginx.demo.com:31567/返回nginx首页。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
name: ingress-host-bar
spec:
ingressClassName: nginx
rules:
- host: "hello.server.com"
http:
paths:
# Prefix 前缀匹配
- pathType: Prefix
path: "/"
backend:
service:
name: hello-server
port:
number: 8000
- host: "nginx.demo.com"
http:
paths:
- pathType: Prefix
path: "/nginx(/|$)(.*)" # 把请求会转给下面的服务,下面的服务一定要能处理这个路径,不能处理就是404
backend:
service:
name: nginx-demo ## java,比如使用路径重写,去掉前缀nginx
port:
number: 8000
当我们在浏览器再次访问:http://nginx.demo.com:31567/,这个时候由于Ingress没有配置规则,所以返回404.
当我们访问http://nginx.demo.com:31567/nginx的时候则会返回nginx首页,因为当请求到达Ingress后,会进行处理,将/nginx路径去掉后再转发到nginx-demo服务,即这个Nginx首页是 nginx-demo Pod 返回的。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-limit-rate
annotations:
nginx.ingress.kubernetes.io/limit-rps: "1"
spec:
ingressClassName: nginx
rules:
- host: "limit.demo.com"
http:
paths:
# Exact 精确匹配
- pathType: Exact
path: "/"
backend:
service:
name: nginx-demo
port:
number: 8000
在hosts文件配置 域名映射
47.102.211.162 limit.demo.com #K8s Ingress 限流
在浏览器访问:http://limit.demo.com:31567/
2.8 存储抽象 2.8.1 NFS环境搭建#所有机器安装 yum install -y nfs-utils #nfs主节点 即在主节点暴露/nfs/data/目录,给其他节点同步 echo "/nfs/data/ *(insecure,rw,sync,no_root_squash)" > /etc/exports mkdir -p /nfs/data systemctl enable rpcbind --now systemctl enable nfs-server --now #配置生效 exportfs -r # 确认 exportfs
# 在其他节点查看主节点可以挂在的目录 172.31.0.149为主节点内网ip showmount -e 172.31.0.149 #执行以下命令挂载 nfs 服务器上的共享目录到本机路径 /root/nfsmount mkdir -p /nfs/data # 同步主节点的目录 172.31.0.149:/nfs/data 远程节点目录 同步至本机/nfs/data目录 mount -t nfs 172.31.0.149:/nfs/data /nfs/data # 写入一个测试文件 echo "hello nfs server" > /nfs/data/test.txt
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-pv-demo
name: nginx-pv-demo
spec:
replicas: 2
selector:
matchLabels:
app: nginx-pv-demo
template:
metadata:
labels:
app: nginx-pv-demo
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
volumes:
- name: html
nfs:
server: 172.31.0.149
path: /nfs/data/nginx-pv
volumeMounts 进行数据挂载 ,即将容器内部/usr/share/nginx/html目录挂载到本机的/nfs/data/nginx-pv目录。注意nfs.server为主机的内网ip。
我们在主机目录下创建一个index.html文件。
然后在Pod看文件是否同步。
可以看到Pod里的Nginx容器目录也已经同步了主机的文件。
注意:如果我们把Pod删除了,但是nfx里挂载的文件不会清除。
PV:持久卷(Persistent Volume),将应用需要持久化的数据保存到指定位置
PVC:持久卷申明(Persistent Volume Claim),申明需要使用的持久卷规格
创建准备目录:
#nfs主节点 mkdir -p /nfs/data/01 mkdir -p /nfs/data/02 mkdir -p /nfs/data/03创建PV
注意 服务IP为主节点的私网Ip
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv01-10m
spec:
capacity:
storage: 10M
accessModes:
- ReadWriteMany
storageClassName: nfs
nfs:
path: /nfs/data/01
server: 172.31.0.149
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv02-1gi
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
storageClassName: nfs
nfs:
path: /nfs/data/02
server: 172.31.0.149
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv03-3gi
spec:
capacity:
storage: 3Gi
accessModes:
- ReadWriteMany
storageClassName: nfs
nfs:
path: /nfs/data/03
server: 172.31.0.149
# 使用命令查看 kubectl get persistentvolume创建PVC
注意:storageClassName需要与我们上面创建的pv池的storageClassName一致。
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: nginx-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 200Mi
storageClassName: nfs
也可以通过kubectl delete pvc 名称 删除PVC,
创建Pod绑定PVCapiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-deploy-pvc
name: nginx-deploy-pvc
spec:
replicas: 2
selector:
matchLabels:
app: nginx-deploy-pvc
template:
metadata:
labels:
app: nginx-deploy-pvc
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
volumes:
- name: html
persistentVolumeClaim:
claimName: nginx-pvc
如果想要删除Pod,删除pvc后也会释放pv池中绑定的存储空间。
测试:
我们在主机的/nfs/data/02目录里创建一个index.html文件:
在Pod的nginx容器内部查看是否同步:
ConfigMap 抽取应用配置,并且可以自动更新。
redis示例首先准备一个redis.conf文件:
# 创建配置,redis保存到k8s的etcd; kubectl create cm redis-conf --from-file=redis.conf
apiVersion: v1
data: #data是所有真正的数据,key:默认是文件名 value:配置文件的内容
redis.conf: |
appendonly yes
kind: ConfigMap
metadata:
name: redis-conf
namespace: default
创建Pod
apiVersion: v1
kind: Pod
metadata:
name: redis
spec:
containers:
- name: redis
image: redis
command:
- redis-server
- "/redis-master/redis.conf" #指的是redis容器内部的位置
ports:
- containerPort: 6379
volumeMounts:
- mountPath: /data
name: data
- mountPath: /redis-master
name: config
volumes:
- name: data
emptyDir: {}
- name: config
configMap:
name: redis-conf
items:
- key: redis.conf
path: redis.conf
检查默认配置:
kubectl exec -it redis -- redis-cli 127.0.0.1:6379> ConFIG GET appendonly 127.0.0.1:6379> ConFIG GET requirepass
使用kubectl edit cm redis-conf命令修改ConfigMap:
apiVersion: v1
kind: ConfigMap
metadata:
name: example-redis-config
data:
redis-config: |
maxmemory 2mb
maxmemory-policy allkeys-lru
检查配置是否更新:
kubectl exec -it redis -- redis-cli 127.0.0.1:6379> ConFIG GET maxmemory 127.0.0.1:6379> ConFIG GET maxmemory-policy
检查指定文件内容是否已经更新:修改了CM。Pod里面的配置文件会跟着变。
使用命令kubectl exec -it redis -- /bin/bash进入Pod内部/redis-master目录,查看Redis配置文件:
我们的配置文件已经改变,用命令获取Redis配置的值,显示不是配置文件的值是因为未重启Pod。
配置值未更改,因为需要重新启动 Pod 才能从关联的 ConfigMap 中获取更新的值。
原因:我们的Pod部署的中间件自己本身没有热更新能力
Secret 对象类型用来保存敏感信息,例如密码、OAuth 令牌和 SSH 密钥。 将这些信息放在 secret 中比放在 Pod 的定义或者 容器镜像 中来说更加安全和灵活。
以阿里云镜像仓库为例,也可以以dockerhub为例。创建一个私有仓库。
kubectl create secret docker-registry liushihao-docker --docker-server=registry-vpc.cn-shanghai.aliyuncs.com/lsh_k8s_repository/private_k8s_repository --docker-username=liushihaowyt --docker-password=liushihao! --docker-email=1692312138@qq.com ##命令格式 kubectl create secret docker-registry regcred --docker-server=<你的镜像仓库服务器> --docker-username=<你的用户名> --docker-password=<你的密码> --docker-email=<你的邮箱地址>
# 查看secret kubectl get secret # 查看secret详细信息 kubectl get secret liushihao-docker -oyaml
创建一个Pod,但是镜像我们指定我们私有仓库中的镜像,(docker logout 登出状态):
apiVersion: v1
kind: Pod
metadata:
name: private-nginx
spec:
containers:
- name: private-nginx
image: registry.cn-shanghai.aliyuncs.com/lsh_k8s_repository/private_k8s_repository:v1.0
同样是刚刚创建Pod的yml文件,但是加上指定秘钥
apiVersion: v1
kind: Pod
metadata:
name: private-nginx
spec:
containers:
- name: private-nginx
image: registry.cn-shanghai.aliyuncs.com/lsh_k8s_repository/private_k8s_repository:v1.0
imagePullSecrets:
- name: liushihao-docker



