本文主要介绍k8s
的核心概念:
Namespace 名称空间,用来对集群资源进行隔离划分,默认只隔离资源,不隔离网络
使用命令行的方式创建名称空间:
# 获取所有的名称空间 全称namespace 或者缩写ns都可以
kubectl get ns
# 创建一个名称空间
kubectl create ns hello
# 删除名称空间
kubectl delete ns hello
# 版本
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.yml
Pod是运行中的一组容器,Pod是Kubernetes中应用的最小单位。
#创建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名字
创建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 mynginx
同样可以使用可视化界面进行操作:
执行:进入容器内部。
日志:查看容器运行日志。
删除
#kubectl get查看应用更详细信息
kubectl get pod -owide
# 每个PodK8s都会分配一个IP。使用Pod的Id+容器里运行的端口访问
#使用curl命令访问nginx
curl 192.168.58.195
#进入容器
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 default
# 清除所有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 mytomcat
# my-dep 部署名称 --image=nginx 选择nginx为镜像 --replicas=3指定副本数为3
kubectl create deployment my-dep --image=nginx --replicas=3
kubectl get deploy
kubectl get pod -owide
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
# 手动扩容
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
现在将我们的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 image
除了Deployment,k8s还有 StatefulSet 、DaemonSet 、Job 等 类型资源。我们都称为 工作负载。
有状态应用使用 StatefulSet 部署,无状态应用使用 Deployment 部署。
将一组 Pods 公开为网络服务的抽象方法。Pod的服务发现与负载均衡。
修改三个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
当我们使用之前的扩缩容的命令修改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范围在 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/
#所有机器安装
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。
然后在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
注意 服务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
注意:storageClassName
需要与我们上面创建的pv池的storageClassName
一致。
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: nginx-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 200Mi
storageClassName: nfs
也可以通过kubectl delete pvc 名称
删除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
如果想要删除Pod,删除pvc后也会释放pv池中绑定的存储空间。
测试:
我们在主机的/nfs/data/02
目录里创建一个index.html
文件:
在Pod的nginx容器内部查看是否同步:
ConfigMap 抽取应用配置,并且可以自动更新。
# 创建配置,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