资源创建方式
- 命令行
- yaml
NameSpace
名称空间用来隔离资源
kubectl create ns hello
kubectl delete ns hello
apiVersion: v1
kind: Namespace
metadata:
name: hello
kubectl apply -f hello.yaml
kubectl delete -f hello.yaml
pod
运行中的一组容器,Pod是kubernetes中应用的最小单位.
# 创建一个mytest命名空间
kubectl create ns mytest
# 在mytest里运行一个镜像
kubectl run nginx --image=nginx -n mytest
# 查看pod
kubectl get pod -n mytest
# 描述,排错时使用
kubectl describe pod mynginx -n mytest
# 删除
kubectl delete pod mynginx -n mytest
# 查看Pod的运行日志
kubectl logs mynginx -n mytest
# 每个Pod - k8s都会分配一个ip
kubectl get pod -owide -n mytest
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mynginx 1/1 Running 0 60s 192.168.51.197 k8s-node-001 <none> <none>
# 集群中的任意机器可以通过pod分配的IP进行访问
curl 192.168.51.197
# 进入pod里面执行命令
kubectl exec -it mynginx -n mytest -- /bin/bash
- 使用yaml创建(也可在k8s dashboard创建)
apiVersion: v1
kind: Pod
metadata:
labels:
run: mynginx
name: mynginx
# namespace: default
spec:
containers:
- image: nginx
name: mynginx
# 创建
kubectl apply -f nginx.yaml
# 删除
kubectl delete -f nginx.yaml
- 一个pod部署多个容器(相同的应用不能放在一个pod上)
apiVersion: v1
kind: Pod
metadata:
labels:
run: myapp
name: myapp
namespace: mytest
spec:
containers:
- image: nginx
name: nginx
- image: tomcat:8.5.68
name: tomcat
[root@k8s-master-001 ~]# kubectl apply -f myapp.yaml
[root@k8s-master-001 ~]# kubectl get pod -owide -n mytest
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myapp 2/2 Running 0 3m4s 192.168.74.195 k8s-node-002 <none> <none>
Deployment
控制Pod,使Pod拥有多副本,自愈,扩缩容等能力
# 清除所有Pod,比较下面两个命令有何不同效果?
kubectl delete pod myapp mynginx -n mytest (删除多个pod空格隔开)
kubectl run mynginx --image=nginx
kubectl create deployment mytomcat --image=tomcat:8.5.68
# 自愈能力,删除这个pod之后自动拉起一个新的pod
kubectl delete pod mytomcat-6f5f895f4f-rcb5m
# 这时删除需要,删除这次deploy
[root@k8s-master-001 ~]# kubectl delete deploy mytomcat
deployment.apps "mytomcat" deleted
- 资源限制
kubectl -n mytestset resources deployment my-dep--limits=cpu=200m,memory=512Mi
- 弹性伸缩,当cpu使用超过80%,
kubectl autoscale deployment nginx --min=4 --max=5 --cpu-percent=80 -n default
- 多副本
kubectl create deployment my-dep --image=nginx --replicas=3 -n mytest
[root@k8s-master-001 ~]# kubectl get deploy -n mytest
NAME READY UP-TO-DATE AVAILABLE AGE
my-dep 3/3 3 3 58s
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: my-dep
name: my-dep
namespace: mytest
spec:
replicas: 3
selector:
matchLabels:
app: my-dep
template:
metadata:
labels:
app: my-dep
spec:
containers:
- image: nginx
name: nginx
- 扩缩容 通过命令观察变化
watch -n 1 kubectl get pod -n mytest
# 副本增加到5个
kubectl scale --replicas=5 deployment/my-dep
# 副本减少到3个
kubectl scale --replicas=3 deployment/my-dep
# 编辑yaml配置进行缩容
kubectl edit deployment my-dep
#修改 replicas
自愈&故障转移
- 停机
关宿主机模拟
- 删除pod
docker stop xxx
容器崩溃
容器崩溃
滚动更新
- 查看deployment使用了什么镜像
kubectl get deploy my-dep -n mytest -oyaml
kubectl set image deployment/my-dep nginx=nginx:1.16.1 --record
kubectl rollout status deployment/my-dep
# 修改 kubectl edit deployment/my-dep
版本回退
#历史记录
[root@k8s-master-001 ~]# kubectl rollout history deployment/my-dep -n mytest
deployment.apps/my-dep
REVISION CHANGE-CAUSE
1 <none>
2 kubectl set image deployment/my-dep nginx=nginx:1.16.1 --record=true --namespace=mytest
#查看某个历史详情
kubectl rollout history deployment/my-dep --revision=2
#回滚(回到上次)
[root@k8s-master-001 ~]# kubectl rollout undo deployment/my-dep -n mytest
deployment.apps/my-dep rolled back
#回滚(回到指定版本)
[root@k8s-master-001 ~]# kubectl rollout undo deployment/my-dep --to-revision=1 -n mytest
deployment.apps/my-dep rolled back
其他工作负载
除了Deployment,k8s还有 StatefulSet 、DaemonSet 、Job 等 类型资源。我们都称为 工作负载。 有状态应用使用 StatefulSet 部署,无状态应用使用 Deployment 部署 https://kubernetes.io/zh/docs/concepts/workloads/controllers/
Deployment: 无状态应用部署,比如微服务,提供多副本等功能
StatefulSet: 有状态应用部署,比如redis,提供稳定的存储、网络等功能
DaemonSet: 守护型应用部署,比如日志收集组件,在每个机器都运行一份
Job/Crontab: 定时任务部署,比如垃圾清理组件,可以在指定时间运行
Service ClusterIP 模式(默认) 集群内部访问
将一组Pods公开为网络服务的抽象方法
# 暴露Deploy
kubectl expose deployment my-dep --port=8000 --target-port=80 --type=ClusterIP
# 删除service
[root@k8s-master-001 ~]# kubectl delete service my-dep -n mytest
service "my-dep" deleted
# 查看service暴露的IP和端口
[root@k8s-master-001 ~]# kubectl get service -n mytest
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-dep ClusterIP 10.96.156.29 <none> 8000/TCP 3m18s
#使用标签检索Pod
kubectl get pod -l app=my-dep
- 创建一个新的pod测试访问svc ip和svc域名
kubectl create deploy my-tomcat --image=tomcat -n mytest
# 查看pod name
kubectl get pod -n mytest
# 进入pod测试
kubectl exec -it my-tomcat-b4c9b6565-xbll7 -n mytest -- /bin/bash
# 使用IP和域名都可以访问
root@my-tomcat-b4c9b6565-xbll7:/usr/local/tomcat# curl 10.96.156.29:8000
3333
root@my-tomcat-b4c9b6565-xbll7:/usr/local/tomcat# curl 10.96.156.29:8000
2222
root@my-tomcat-b4c9b6565-xbll7:/usr/local/tomcat# curl 10.96.156.29:8000
11111
root@my-tomcat-b4c9b6565-xbll7:/usr/local/tomcat# curl my-dep.mytest.svc:8000
2222
root@my-tomcat-b4c9b6565-xbll7:/usr/local/tomcat# curl my-dep.mytest.svc:8000
11111
root@my-tomcat-b4c9b6565-xbll7:/usr/local/tomcat# curl my-dep.mytest.svc:8000
2222
Service NodePort 模式(集群外也可以访问)
# 先删除刚刚创建的svc
[root@k8s-master-001 ~]# kubectl delete svc my-dep -n mytest
# 使用svc的nodeport创建一次部署
kubectl expose deployment my-dep --port=8000 --target-port=80 --type=NodePort -n mytest
# 查看集群IP
[root@k8s-master-001 ~]# kubectl get svc -n mytest
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-dep NodePort 10.96.118.198 <none> 8000:30451/TCP 110s
service "my-dep" deleted
# 这时在浏览器中使用节点IP+30451也可以访问到集群
NodePort范围在 30000-32767 之间
Ingress
Service的统一网关入口
- 安装
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.47.0/deploy/static/provider/baremetal/deploy.yaml
#修改镜像
vi deploy.yaml
#将image的值改为如下值:
registry.cn-guangzhou.aliyuncs.com/leoiceo_k8s_images/ingress-nginx-controller:v0.46.0
# 部署
kubectl apply -f deploy.yaml
# 检查安装的结果
[root@k8s-master-001 ~]# kubectl get pod,svc -n ingress-nginx
NAME READY STATUS RESTARTS AGE
pod/ingress-nginx-admission-create-vgpnx 0/1 Completed 0 8m14s
pod/ingress-nginx-admission-patch-frwc8 0/1 Completed 0 8m14s
pod/ingress-nginx-controller-576cb8ff96-4rlmn 1/1 Running 0 8m14s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/ingress-nginx-controller NodePort 10.96.172.45 <none> 80:30637/TCP,443:31315/TCP 8m14s
service/ingress-nginx-controller-admission ClusterIP 10.96.71.227 <none> 443/TCP 8m14s
# 最后别忘记把svc暴露的端口要放行
使用
测试环境
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-guangzhou.aliyuncs.com/leoiceo_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
- 域名访问 编写一个yaml文件创建ingress规则
ingress-rule.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-host-bar
spec:
ingressClassName: nginx
rules:
- host: "hello-k8s.imdst.com"
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: hello-server
port:
number: 8000
- host: "demo-k8s.imdst.com"
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: nginx-demo
port:
number: 8000
kubectl apply -f ingress-rule.yaml
# 查看ingress域名
[root@k8s-master-001 ~]# kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress-host-bar nginx hello-k8s.imdst.com,demo-k8s.imdst.com 10.3.100.67 80 2m55s
# 查看ingress入口IP
[root@k8s-master-001 ~]# kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 10.96.172.45 <none> 80:30637/TCP,443:31315/TCP 30m
ingress-nginx-controller-admission ClusterIP 10.96.71.227 <none> 443/TCP 30m
# 将域名绑定到hosts进行测试
echo "10.96.172.45 hello-k8s.imdst.com demo-k8s.imdst.com" >> /etc/hosts
# curl进行访问测试,也可以浏览器中访问,在本机绑定节点IP
[root@k8s-master-001 ~]# curl hello-k8s.imdst.com
Hello World!
[root@k8s-master-001 ~]# curl demo-k8s.imdst.com
welcome to nginx
- 路径重写
# 由于上面已经创建了ingress规则,可以直接通过以下命令去编辑yaml即可以生效
kubectl edit ing ingress-host-bar
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-k8s.imdst.com"
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: hello-server
port:
number: 8000
- host: "demo-k8s.imdst.com"
http:
paths:
- pathType: Prefix
path: "/nginx(/|$)(.*)" # 把请求会转给下面的服务,下面的服务一定要能处理这个路径,不能处理就是404
backend:
service:
name: nginx-demo ## java,比如使用路径重写,去掉前缀nginx
port:
number: 8000
#测试访问
curl demo-k8s.imdst.com/nginx/ 等同于访问 demo-k8s.imdst.com/
curl demo-k8s.imdst.com/nginx/nginx/ 等同于访问 demo-k8s.imdst.com/nginx/
- 流量限制
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: "haha-k8s.imdst.com"
http:
paths:
- pathType: Exact
path: "/"
backend:
service:
name: nginx-demo
port:
number: 8000
存储抽象
- 搭建一个nfs环境进行测试,如果有公有云环境,可以直接购买nfs服务挂载到k8s各个节点
k8s-master : nfs主节点 /nfs/data
k8s-slave-001 : nfs-client /nfs/data
k8s-slave-002 : nfs-client /nfs/data
# 所有节点安装nfs-utils
yum install -y nfs-utils
#nfs主节点
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
#从节点
showmount -e 10.3.100.66
#执行以下命令挂载 nfs 服务器上的共享目录到本机路径 /root/nfsmount
mkdir -p /nfs/data
mount -t nfs 10.3.100.66:/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: 10.3.100.66
path: /nfs/data/nginx-pv
# 提前创建挂载目录
mkdir -p /nfs/data/nginx-pv
echo "this is test nginx-pv-demo pages" > /nfs/data/nginx-pv/index.html
kubectl apply -f nginx-pv-demo.yaml
# 查看pod状态
kubectl get pod
# 查看部署运行中的状态
kubectl describe pod nginx-pv-demo
# 暴露Deploy
kubectl expose deployment nginx-pv-demo --port=8000 --target-port=80
# 查看svc ip,进行测试
kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-pv-demo ClusterIP 10.96.192.211 <none> 8000/TCP 3m34s
# 多次测试发现都是返回相同的index页面
[root@k8s-master-001 ~]# curl 10.96.192.211:8000
this is test nginx-pv-demo pages
PV&PVC
PV:持久卷(Persistent Volume),将应用需要持久化的数据保存到指定位置
PVC:持久卷申明(Persistent Volume Claim),申明需要使用的持久卷规格 * 创建pv池
#nfs主节点
mkdir -p /nfs/data/01
mkdir -p /nfs/data/02
mkdir -p /nfs/data/03
- 创建PV
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv01-10m
spec:
capacity:
storage: 10M
accessModes:
- ReadWriteMany
storageClassName: nfs
nfs:
path: /nfs/data/01
server: 10.3.100.66
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv02-1gi
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
storageClassName: nfs
nfs:
path: /nfs/data/02
server: 10.3.100.66
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv03-3gi
spec:
capacity:
storage: 3Gi
accessModes:
- ReadWriteMany
storageClassName: nfs
nfs:
path: /nfs/data/03
server: 10.3.100.66
# 创建PV
[root@k8s-master-001 ~]# kubectl apply -f pv.yaml
persistentvolume/pv01-10m created
# 查看已经创建的PV
[root@k8s-master-001 ~]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv01-10m 10M RWX Retain Available nfs 34s
pv02-1gi 1Gi RWX Retain Available nfs 34s
pv03-3gi 3Gi RWX Retain Available nfs 34s
- PVC创建与PV绑定
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: nginx-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 200Mi
storageClassName: nfs
[root@k8s-master-001 ~]# kubectl apply -f pvc.yaml
persistentvolumeclaim/nginx-pvc created
[root@k8s-master-001 ~]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
nginx-pvc Bound pv02-1gi 1Gi RWX nfs 5s
[root@k8s-master-001 ~]#
创建Pod绑定PVC
apiVersion: 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
[root@k8s-master-001 ~]# kubectl apply -f nginx-pvc.yaml
deployment.apps/nginx-deploy-pvc created
[root@k8s-master-001 ~]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
nginx-pvc Bound pv02-1gi 1Gi RWX nfs 2m38s
# 这时发现 pv02-1gi 已经被绑定了
[root@k8s-master-001 ~]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv01-10m 10M RWX Retain Available nfs 8m2s
pv02-1gi 1Gi RWX Retain Bound default/nginx-pvc nfs 8m2s
pv03-3gi 3Gi RWX Retain Available nfs 8m2s
ConfigMap
抽取应用配置,并且可以自动更新 * 测试配置redis.conf
appendonly yes
- 创建配置集
# 创建配置,redis保存到k8s的etcd;
[root@k8s-master-001 ~]# kubectl create cm redis-conf --from-file=redis.conf
configmap/redis-conf created
[root@k8s-master-001 ~]# kubectl get cm
NAME DATA AGE
kube-root-ca.crt 1 8d
redis-conf 1 5s
# 查看配置集
[root@k8s-master-001 ~]# kubectl get cm redis-conf -oyaml
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
[root@k8s-master-001 ~]# kubectl apply -f redis-pod.yaml
pod/redis created
# 等待redis运行
[root@k8s-master-001 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
redis 0/1 ContainerCreating 0 1s
# 进入容器查看配置是否正常加载
[root@k8s-master-001 ~]# kubectl exec -it redis -- /bin/bash
root@redis:/data# cd /redis-master/
root@redis:/redis-master# ls
redis.conf
root@redis:/redis-master# cat redis.conf
appendonly yes
# 退出去修改配置
[root@k8s-master-001 ~]# kubectl get cm
NAME DATA AGE
kube-root-ca.crt 1 8d
redis-conf 1 13m
[root@k8s-master-001 ~]# kubectl edit cm redis-conf
configmap/redis-conf edited
给Redis设置一个密码
requirepass 123456
# 再次登陆容器查看配置变化
kubectl exec -it redis -- redis-cli
127.0.0.1:6379> CONFIG GET appendonly
127.0.0.1:6379> CONFIG GET requirepass # 需要重启容器才会生效
检查指定文件内容是否已经更新
修改了CM。Pod里面的配置文件会跟着变配置值未更改,因为需要重新启动 Pod 才能从关联的 ConfigMap 中获取更新的值。
原因:我们的Pod部署的中间件自己本身没有热更新能力
Secret
Secret 对象类型用来保存敏感信息,例如密码、OAuth 令牌和 SSH 密钥。 将这些信息放在 secret 中比放在 Pod 的定义或者 容器镜像 中来说更加安全和灵活。
- 命令格式
kubectl create secret docker-registry leoiceo-secret \
--docker-server=<你的镜像仓库服务器> \
--docker-username=<你的用户名> \
--docker-password=<你的密码> \
--docker-email=<你的邮箱地址>
apiVersion: v1
kind: Pod
metadata:
name: private-php-fpm
spec:
containers:
- name: private-php-fpm
image: registry.cn-guangzhou.aliyuncs.com/leoiceo/php-fpm:7.4
imagePullSecrets:
- name: leoiceo-secret