赞
踩
https://note.youdao.com/ynoteshare/index.html?id=bc7bee305611b52d6900ba209a92bd4d&type=note&_time=1694072007342
K8S官网文档:https://kubernetes.io/zh/docs/home/
K8S 是Kubernetes的全称,源于希腊语,意为“舵手”或“飞行员”,官方称其是:用于自动部署、扩展和管理“容器化(containerized)应用程序”的开源系统。翻译成大白话就是:“K8S 是负责自动化运维管理多个跨机器 Docker 程序的集群”。
kubectl是apiserver的客户端工具,工作在命令行下,能够连接apiserver实现各种增删改查等操作
kubectl官方使用文档:https://kubernetes.io/zh/docs/reference/kubectl/overview/
K8s 中,命名空间(Namespace) 提供一种机制,将同一集群中的资源划分为相互隔离的组。同一命名空间内的资源名称要唯一,命名空间是用来隔离资源的,不隔离网络。
Kubernetes 启动时会创建四个初始命名空间:
# 查看namespace、
kubectl get namespace
#查看kube-system下的pod
kubectl get pods -n kube-system
#查看所有namespace下的pod
kubectl get pods -A
kubectl create namespace yuyang
新建一个名为 my-namespace.yaml 的 YAML 文件,并写入下列内容:
apiVersion: v1
kind: Namespace
metadata:
name: yuyang
然后运行:
kubectl apply -f my-namespace.yaml
删除namesapce
kubectl delete namespace yuyang
kubectl delete -f my-namespace.yaml
Pod 是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。Pod(就像在鲸鱼荚或者豌豆荚中)是一组(一个或多个)容器; 这些容器共享存储、网络、以及怎样运行这些容器的声明。
# 创建pod
kubectl run mynginx --image=nginx:1.14.2
#在指定命名空间创建pod
kubectl run mynginx --image=nginx:1.14.2 -n <namespace>
kubectl run mynginx --image=nginx:1.14.2 -n yuyang #例子
# 获取pod的信息,-owide 表示更详细的显示信息 -n 命名空间 查询对应namespace下的pod
kubectl get pod
kubectl get pod -owide
kubectl get pod -owide -n <namespace-name>
#查看pod的详情
kubectl describe pod <pod-name>
kubectl describe pod <pod-name> -n <namespace-name>
# 查看Pod的运行日志
kubectl logs <pod-name>
# 删除pod
kubectl delete pod <pod-name>
kubectl delete pod <pod-name> -n <namespace>
kubectl describe pod
#vim nginx-pod.yaml
apiVersion: v1 #版本
kind: Pod #类型
metadata: #以上是默认格式
labels:
run: mynginx #标签别名
name: mynginx #pod名字
spec:
containers:
- name: nginx
image: nginx:1.14.2 #无版本号则拉取最新的
ports:
- containerPort: 80
然后运行:
kubectl apply -f nginx-pod.yaml
删除pod
kubectl delete -f nginx-pod.yaml
一个pod运行多个容器
apiVersion: v1
kind: Pod
metadata:
labels:
run: myapp
name: myapp
spec:
containers:
- image: nginx:1.14.2
name: nginx
- image: tomcat:9.0.55
Deployment负责创建和更新应用程序的实例,使Pod拥有多副本,自愈,扩缩容等能力。创建Deployment后,Kubernetes Master 将应用程序实例调度到集群中的各个节点上。如果托管实例的节点关闭或被删除,Deployment控制器会将该实例替换为群集中另一个节点上的实例。这提供了一种自我修复机制来解决机器故障维护问题。
使用kubectl create deployment 命令创建一个应用部署deployment 与 pod
#my-tomcat表示pod的名称 --image表示镜像的地址 kubectl create deployment my-tomcat --image=tomcat:9.0.55 #查看一下deployment的信息 kubectl get deployment #删除deployment kubectl delete deployment my-tomcat #查看Pod打印的日志 kubectl logs my-tomcat-6d6b57c8c8-n5gm4 #使用 exec 可以在Pod的容器中执行命令 kubectl exec -it my-tomcat-6d6b57c8c8-n5gm4 - env #使用 env 命令查看环境变量 kubectl exec -it my-tomcat-6d6b57c8c8-n5gm4 - ls / # 查看容器的根目录下面内容 kubectl exec -it my-tomcat-6d6b57c8c8-n5gm4 - sh #进入Pod容器内部并执行bash命令,如果想退出容器可以使用exit命令 kubectl exec -it my-tomcat-6d6b57c8c8-n5gm4 - sh
kubectl create my-tomcat --image=tomcat:9.0.55 #创建pod
kubectl create deployment my-tomcat --image=tomcat:9.0.55 #创建deployment
#查看pod信息,-w意思是一直等待观察pod信息的变动
kubectl get pod -w
开另外一个命令窗口执行如下命令,同时观察之前命令窗口的变化情况
kubectl delete pod my-tomcat-67975b6b59-4np5j
可以看到之前的tomcat的pod被销毁了,但是又重新启动一个新的tomcat pod ,这是k8s的服务自愈功能,不需要运维人员干预
# 创建3个副本
kubectl create deployment my-tomcat --image=tomcat:9.0.55 --replicas=3
apiVersion: apps/v1 kind: Deployment metadata: labels: app: my-tomcat name: my-tomcat spec: replicas: 3 selector: matchLabels: app: my-tomcat template: metadata: labels: app: my-tomcat spec: containers: - image: tomcat:9.0.55 name: tomcat
# 扩容到5个pod
kubectl scale --replicas=5 deployment my-tomcat
# 缩到3个pod
kubectl scale --replicas=3 deployment my-tomcat
扩容到5个pod
缩容到3个pod
对my-tomcat这个deployment进行滚动升级和回滚,将tomcat版本由tomcat:9.0.55升级到tomcat:10.1.11,再回滚到tomcat:9.0.55
滚动升级:
kubectl set image deployment my-tomcat tomcat=tomcat:10.1.11 --record
可以执行 kubectl get pod -w 观察pod的变动情况,可以看到有的pod在销毁,有的pod在创建
查看pod信息
kubectl get pod
查看某个pod的详细信息,发现pod里的镜像版本已经升级了
kubectl describe pod my-tomcat-85c5c8f685-lnkfm
版本回滚:
查看历史版本
kubectl rollout history deploy my-tomcat
回滚到上一个版本
kubectl rollout undo deployment my-tomcat #--to-revision 参数可以指定回退的版本
#回滚(回到指定版本)
kubectl rollout undo deployment/my-dep --to-revision=2
集群内访问(在集群里任一worker节点都可以访问)
curl 172.20.125.82:8080
集群外部访问
当在集群之外访问是发现无法访问,那么集群之外的客户端如何才能访问呢?这就需要service服务了
Service是一个抽象层,它定义了一组Pod的逻辑集,并为这些Pod支持外部流量暴露、负载均衡和服务发现。
尽管每个Pod 都有一个唯一的IP地址,但是如果没有Service,这些IP不会暴露在群集外部。Service允许您的应用程序接收流量。Service也可以用在ServiceSpec标记type的方式暴露,type类型如下:
命令行的方式
kubectl expose deployment my-tomcat --name=tomcat --port=8080 --type=NodePort
#查看service信息,port信息里冒号后面的端口号就是对集群外暴露的访问接口
# NodePort范围在 30000-32767 之间
kubectl get svc -o wide
使用集群节点的ip加上暴露的端口就可以访问
tomcat版本太高返回404的解决办法:进入tomcat容器,把 webapps 目录删除,再把 webapps.dist 重命名为 webapps 即可。
# vim mytomcat-service.yaml apiVersion: v1 kind: Service metadata: labels: app: my-tomcat name: my-tomcat spec: ports: - port: 8080 # service的虚拟ip对应的端口,在集群内网机器可以访问用service的虚拟ip加该端口号访问服务 nodePort: 30001 # service在宿主机上映射的外网访问端口,端口范围必须在30000-32767之间 protocol: TCP targetPort: 8080 # pod暴露的端口,一般与pod内部容器暴露的端口一致 selector: app: my-tomcat type: NodePort
执行如下命令创建service:
kubectl apply -f mytomcat-service.yaml
Volume指的是存储卷,包含可被Pod中容器访问的数据目录。容器中的文件在磁盘上是临时存放的,当容器崩溃时文件会丢失,同时无法在多个Pod中共享文件,通过使用存储卷可以解决这两个问题。
Kubernetes支持很多类型的卷。Pod可以同时使用任意数目的卷类型。临时卷类型的生命周期与Pod相同,但持久卷可以比 Pod 的存活期长。当Pod不再存在时,Kubernetes也会销毁临时卷;不过 Kubernetes不会销毁持久卷。对于给定Pod 中任何类型的卷,在容器重启期间数据都不会丢失。
卷的核心是一个目录,其中可能存有数据,Pod中的容器可以访问该目录中的数据。所采用的不同卷的类型将决定该目录如何形成的、使用何种介质保存数据以及目录中存放的内容。常用的卷类型有configMap、emptyDir、local、nfs、secret等。
ConfigMap:可以将配置文件以键值对的形式保存到ConfigMap 中,并且可以在Pod 中以文件或环境变量的形式使用。ConfigMap可以用来存储不敏感的配置信息,如应用程序的配置文件。
EmptyDir:是一个空目录,可以在Pod中用来存储临时数据,当Pod被删除时,该目录也会被删除。
Local:将本地文件系统的目录或文件映射到Pod 中的一个Volume中,可以用来在Pod中共享文件或数据。
NFS:将网络上的一个或多个NFS共享目录挂载到Pod中的Volume中,可以用来在多个Pod之间共享数据。
Secret:将敏感信息以密文的形式保存到Secret中,并且可以在Pod中以文件或环境变量的形式使用。Secret可以用来存储敏感信息,如用户名密码、证书等。
使用卷时,在.spec.volumes 字段中设置为Pod提供的卷,并在.spec.containers[*].volumeMounts 字段中声明卷在容器中的挂载位置。容器中的进程看到的文件系统视图是由它们的容器镜像的初始内容以及挂载在容器中的卷(如果定义了的话)所组成的。其中根文件系统同容器镜像的内容相吻合。任何在该文件系统下的写入操作,如果被允许的话,都会影响接下来容器中进程访问文件系统时所看到的内容。
apiVersion: v1
kind: Pod
metadata:
name: configmap-pod
spec:
containers:
- name: test
image: busybox:1.28
volumeMounts:
..........
volumes:
............
nfs(network filesystem ):网络文件存储系统
安装nfs-server
# 在每个机器。 yum install -y nfs-utils # 在master 执行以下命令 echo "/nfs/data/ *(insecure,rw,sync,no_root_squash)" > /etc/exports # 执行以下命令,启动 nfs 服务;创建共享目录 mkdir -p /nfs/data # 在master执行 systemctl enable rpcbind systemctl enable nfs-server systemctl start rpcbind systemctl start nfs-server # 使配置生效 exportfs -r #检查配置是否生效 exportfs
配置nfs-client
# nfs-server节点的ip
showmount -e 192.168.11.101
mkdir -p /nfs/data
mount -t nfs 192.168.11.101:/nfs/data /nfs/data #192.168.11.101 是主节点是ip地址
nfs方式数据挂载
相对于emptyDir和hostPath,nfs这种 Volume类型的最大特点就是不依赖Kuberees Volume的底层基础设施由独立的存储系统管理,与Kubernetes集群是分离的。数据被持久化后,即使整个Kubernetes崩溃也不会受损。
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: 192.168.11.101 path: /nfs/data/nginx-pv
Volume 提供了非常好的数据持久化方案,不过在可管理性上还有不足。前面 nfs 例子来说,要使用 Volume, Pod 必须事先知道以下信息:
但是 Pod 通常是由应用的开发人员维护,而 Volume 则通常是由存储系统的管理员维护。开发人员要获得上面的信息,要么询问管理员,要么自己就是管理员。这样就带来一个管理上的问题:应用开发人员和系统管理员的职责耦合在一起了。如果系统规模较小或者对于开发环境,这样的情况还可以接受,当集群规模变大,特别是对于生产环境,考虑到效率和安全性,这就成了必须要解决的问题。
Kubernetes给出的解决方案是Persistent Volume和PersistentVolume Claim
。
PersistentVolume(PV)是外部存储系统中的一块存储空间,由管理员创建和维护,将应用需要持久化的数据保存到指定位置
。与Volume一样,PV具有持久性,生命周期独立于Pod。
Persistent Volume Claim (PVC)是对PV的申请(Claim),申明需要使用的持久卷规格
。PVC通常由普通用户创建和维护。需要为Pod分配存储资源时,用户可以创建一个PVC,指明存储资源的容量大小和访问模式(比如只读)等信息,Kubernetes会查找并提供满足条件的PV。有了PersistentVolumeClaim,用户只需要告诉Kubernetes需要什么样的存储资源,而不必关心真正的空间从哪里分配、如何访问等底层细节信息。这些Storage Provider的底层信息交给管理员来处理,只有管理员才应该关心创建PersistentVolume的细节信息。
创建pv
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv
spec:
capacity:
storage: 1Gi #指定容量大小
accessModes: # 访问模式
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
storageClassName: nfs
nfs:
path: /{nfs-server目录名称}
server: {nfs-server IP 地址}
值得注意的是,persistentVolumeReclaimPolicy只适用于一些类型的 PV,如 NFS、HostPath、iSCSI 等。对于一些云平台提供的存储,如 AWS EBS 和 Azure Disk,由于底层提供商会自动处理 PV 的回收问题,因此该属性不适用。
创建pvc
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
storageClassName: nfs # 通过名字进行选择
#selector: 通过标签形式
# matchLabels:
# pv-name: nfs-pv
创建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: 192.168.11.101 --- apiVersion: v1 kind: PersistentVolume metadata: name: pv02-1gi spec: capacity: storage: 1Gi accessModes: - ReadWriteMany storageClassName: nfs nfs: path: /nfs/data/02 server: 192.168.11.101 --- apiVersion: v1 kind: PersistentVolume metadata: name: pv03-3gi spec: capacity: storage: 3Gi accessModes: - ReadWriteMany storageClassName: nfs nfs: path: /nfs/data/03 server: 192.168.11.101
创建PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nginx-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 200Mi
storageClassName: nfs
创建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
在前面的例子中,提前创建了PV,然后通过PVC申请PV并在Pod中使用,这种方式叫作静态供应(Static Provision)与之对应的是动态供应(Dynamical Provision),即如果没有满足PVC条件的PV,会动态创建PV。相比静态供应,动态供应有明显的优势:不需要提前创建PV,减少了管理员的工作量,效率高。动态供应是通过 StorageClass 实现的,StorageClass定义了如何创建PV,但需要注意的是每个StorageClass 都有一个制备器(Provisioner),用来决定使用哪个卷插件制备PV,该字段必须指定才能实现动态创建。
配置动态供应的默认存储类
## 创建了一个存储类 apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: nfs-storage annotations: storageclass.kubernetes.io/is-default-class: "true" provisioner: k8s-sigs.io/nfs-subdir-external-provisioner parameters: archiveOnDelete: "true" ## 删除pv的时候,pv的内容是否要备份 --- apiVersion: apps/v1 kind: Deployment metadata: name: nfs-client-provisioner labels: app: nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: default spec: replicas: 1 strategy: type: Recreate selector: matchLabels: app: nfs-client-provisioner template: metadata: labels: app: nfs-client-provisioner spec: serviceAccountName: nfs-client-provisioner containers: - name: nfs-client-provisioner image: registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images/nfs-subdir-external-provisioner:v4.0.2 # resources: # limits: # cpu: 10m # requests: # cpu: 10m volumeMounts: - name: nfs-client-root mountPath: /persistentvolumes env: - name: PROVISIONER_NAME value: k8s-sigs.io/nfs-subdir-external-provisioner - name: NFS_SERVER value: 192.168.11.101 ## 指定自己nfs服务器地址 - name: NFS_PATH value: /nfs/data ## nfs服务器共享的目录 volumes: - name: nfs-client-root nfs: server: 192.168.11.101 path: /nfs/data --- apiVersion: v1 kind: ServiceAccount metadata: name: nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: default --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: nfs-client-provisioner-runner rules: - apiGroups: [""] resources: ["nodes"] verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["persistentvolumes"] verbs: ["get", "list", "watch", "create", "delete"] - apiGroups: [""] resources: ["persistentvolumeclaims"] verbs: ["get", "list", "watch", "update"] - apiGroups: ["storage.k8s.io"] resources: ["storageclasses"] verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["events"] verbs: ["create", "update", "patch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: run-nfs-client-provisioner subjects: - kind: ServiceAccount name: nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: default roleRef: kind: ClusterRole name: nfs-client-provisioner-runner apiGroup: rbac.authorization.k8s.io --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: leader-locking-nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: default rules: - apiGroups: [""] resources: ["endpoints"] verbs: ["get", "list", "watch", "create", "update", "patch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: leader-locking-nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: default subjects: - kind: ServiceAccount name: nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: default roleRef: kind: Role name: leader-locking-nfs-client-provisioner apiGroup: rbac.authorization.k8s.io
在Kubernetes 中,ConfigMap是一种用于存储非敏感信息的Kubernetes 对象。它用于存储配置数据,如键值对、整个配置文件或JSON数据等。ConfigMap通常用于容器镜像中的配置文件、命令行参数和环境变量等。
ConfigMap可以通过三种方式进行配置数据的注入:
优点
#查看configmap
$ kubectl get configmap/ cm
#查看详细
$ kubectl describe configmap/cm my-config
#删除cm
$ kubectl delete cm my-config
kubectl create configmap my-config --from-literal=key1=value1 --from-literal=key2=value2
apiVersion: v1 kind: ConfigMap metadata: name: my-config data: key1: value1 key2: value2 --- apiVersion: v1 kind: ConfigMap metadata: name: app-config data: application.yml: | name: yuyang
echo-n admin >./username
echo -n 123456 > ./password
kubectl create configmap myconfigmap --from-file=./username --from-file=./password
kubectl create configmap my-config --from-file=config-files/
kubectl create configmap my-config --from-env-file=<env>
使用示例
# docker安装redis
docker run -v /data/redis/redis.conf:/etc/redis/redis.conf \
-v /data/redis/data:/data \
-d --name myredis \
-p 6379:6379 \
redis:latest redis-server /etc/redis/redis.conf
创建ConfigMap
#创建redis.conf
daemonize yes
requirepass root
# 创建配置,redis保存到k8s的etcd
kubectl create cm redis-conf --from-file=redis.conf
#查看资源清单
kubectl get cm redis-conf -oyaml
apiVersion: v1
kind: ConfigMap
metadata:
name: redis-conf
data:
redis.conf: |
maxmemory-policy allkeys-lru
requirepass root
创建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 maxmemory-policy
Secret 对象类型用来保存敏感信息,例如密码、OAuth 令牌和 SSH 密钥。 将这些信息放在 secret 中比放在 Pod 的定义或者 容器镜像 中来说更加安全和灵活。
在 Kubernetes 中,Secrets 通常被用于以下场景:
kubectl create secret generic my-secret --from-literal=username=admin --from-literal=password=admin123
apiVersion: v1
kind: Secret
metadata:
name: my-secret
type: Opaque
data:
username: YWRtaW4= # base64 编码后的用户名 admin
password: MWYyZDFlMmU2N2Rm # base64 编码后的密码 1f2d1e2e67df
注意: 这个 YAML 文件定义了一个名为 my-secret 的 Secret 对象,其中包含了两个 base64 编码后的 key-value 对:username 和 password。
echo -n admin >./username
echo -n 123456 > ./password
kubectl create secret generic mysecret --from-file=./username --from-file=./password
kubectl create secret generic my-config --from-env-file=<env>
docker pull registry.cn-hangzhou.aliyuncs.com/fox666/tulingmall-product:0.0.5
无法从私有镜像仓库拉取镜像,抛出如下错误:
解决方案:使用 docker 的用户信息来生成 secret:
##命令格式
kubectl create secret docker-registry myregistrykey \
--docker-server=<你的镜像仓库服务器> \
--docker-username=<你的用户名> \
--docker-password=<你的密码> \
--docker-email=<你的邮箱地址>
kubectl create secret docker-registry myregistrykey --docker-server=registry.cn-hangzhou.aliyuncs.com --docker-username=fox666 --docker-password=xxx
在创建 Pod 的时候,通过imagePullSecrets来引用刚创建的myregistrykey
apiVersion: v1
kind: Pod
metadata:
name: mall-product
spec:
containers:
- name: tulingmall-product
image: registry.cn-hangzhou.aliyuncs.com/fox666/tulingmall-product:0.0.5
imagePullSecrets:
- name: myregistrykey
Ingress 是一种 Kubernetes 资源类型,它允许在 Kubernetes 集群中暴露 HTTP 和 HTTPS 服务。通过 Ingress,您可以将流量路由到不同的服务和端点,而无需使用不同的负载均衡器。Ingress 通常使用 Ingress Controller 实现,它是一个运行在 Kubernetes 集群中的负载均衡器,它根据Ingress 规则配置路由规则并将流量转发到相应的服务。
这是一个将所有流量都发送到同一 Service 的简单 Ingress 示例:
Ingress 和 Service都是 Kubernetes 中用于将流量路由到应用程序的机制,但它们在路由层面上有所不同:
1)下载ingress配置文件
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.47.0/deploy/static/provider/baremetal/deploy.yaml
[root@k8s-master k8s]# grep image: deploy.yaml
image: k8s.gcr.io/ingress-nginx/controller:v0.46.0@sha256:52f0058bed0a17ab0fb35628ba97e8d52b5d32299fbc03cc0f6c7b9ff036b61a
image: docker.io/jettech/kube-webhook-certgen:v1.5.1
image: docker.io/jettech/kube-webhook-certgen:v1.5.1
#修改镜像
vi deploy.yaml
#1、将image k8s.gcr.io/ingress-nginx/controller:v0.46.0@sha256:52f0058bed0a17ab0fb35628ba97e8d52b5d32299fbc03cc0f6c7b9ff036b61a的值改为如下值:
registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images/ingress-nginx-controller:v0.46.0
2)安装ingress,执行如下命令
kubectl apply -f ingress-controller.yaml
kubectl get pod,svc -n ingress-nginx -owide
官网地址: https://kubernetes.github.io/ingress-nginx/
配置ingress访问规则(就是类似配置nginx的代理转发配置),让ingress将域名tomcat.tuling.com转发给后端的my-tomcat服务,新建一个文件ingress-tomcat.yaml,内容如下:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: web-ingress spec: rules: - host: tomcat.tuling.com #转发域名 http: paths: - pathType: Prefix path: / backend: service: name: my-tomcat port: number: 8080 #service的端口
执行如下命令生效规则:
kubectl apply -f ingress-tomcat.yaml
查看生效的ingress规则:
kubectl get ing
在访问机器配置host, win10客户机在目录: C:\Windows\System32\drivers\etc,在host里增加如下host(ingress部署的机器ip对应访问的域名)
192.168.65.82 tomcat.yuyang.com
配置完后直接在客户机浏览器访问http://tomcat.yuyang.com:30940能正常访问tomcat.
Service是K8S服务的核心,屏蔽了服务细节,统一对外暴露服务接口,真正做到了“微服务”。举个例子,我们的一个服务A,部署了3个备份,也就是3个Pod;对于用户来说,只需要关注一个Service的入口就可以,而不需要操心究竟应该请求哪一个Pod。优势非常明显: 一方面外部用户不需要感知因为Pod . 上服务的意外崩溃、K8S 重新拉起Pod而造成的IP变更,外部用户也不需要感知因升级、变更服务带来的Pod替换而造成的IP变化,另- -方面,Service 还可以做流量负载均衡。
但是,Service 主要负责K8S集群内部的网络拓扑。集群外部需要用Ingress。
Ingress是整个K8S集群的接入层,复杂集群内外通讯。
Ingress和Service的网络拓扑关系图如下:
K8S的网络中主要存在4种类型的通信:
K8S为Pod和Service资源对象分别使用了各自的专有网络,Pod网络由K8S的网络插件配置实现,而Service网络则由K8S集群进行指定。如下图:
K8S使用的网络插件需要为每个Pod配置至少一个特定的地址,即Pod IP。Pod IP地址实际存在于某个网卡(可以是虚拟机设备)上。
而Service的地址却是- -个虚拟IP地址,没有任何网络接口配置在此地址上,它由Kube-proxy借助iptables规则或ipvs规则重定向到本地端口,再将其调度到后端的Pod对象。Service的IP地址 是集群提供服务的接口,也称为Cluster IP。
Pod网络和IP由K8S的网络插件负责配置和管理,具体使用的网络地址可以在管理配置网络插件时进行指定,如10.244.0.0/16网络。 而Cluster网络和IP是由K8S集群负责配置和管理,如10.96.0.0/12网络。
从上图进行总结起来,一个K8S集群包含是三个网络。
用K8S部署Nginx的过程中,K8S内部各组件是如何协同工作的:
在master节点执行一条命令要master部署-个nginx应用(kubectl create deployment nginx – image=nginx)
K8S是- -个基于容器技术的分布式集群管理系统。既然是个分布式系统,那势必有多个Node节点(物理主机或虚拟机),它们共同组成一个分布式集群,并且这些节点中会有一-个Master节点,由它来统一管理Node节点。
如图所示:
首先,Master 节点启动时,会运行一一个kube-apiserver进程,它提供了集群管理的API接口,是集群内各个功能模块之间数据交互和通信的中心枢纽,并且它页提供了完备的集群安全机制。
在Node节点上,使用K8S中的kubelet组件,在每个Node节点上都会运行一-个kubelet进程,它负责向Master汇报自身节,点的运行情况,如Node节点的注册、终止、定时上报健康状况等,以及接收Master发出的命令,创建相应Pod。
在K8S中,Pod是最基本的操作单元,它与docker的容器有略微的不同,因为Pod可能包含- -个或多个容器(可以是docker容器),这些内部的容器是共享网络资源的,即可以通过localhost进行相互访问。
关于Pod内是如何做到网络共享的,每个Pod启动,内部都会启动一个pause容器(google的一 个镜像),它使用默认的网络模式,而其他容器的网络都设置给它,以此来完成网络的共享问题。
如图所示:
该工作由kube-scheduler来完成,整个调度过程通过执行-些列复杂的算法最终为每个Pod 计算出一一个最佳的目标Node,该过程由kube-scheduler进程自动完成。常见的有轮询调度(RR) 。当然也有可能,我们需要将Pod调度到一个指定的Node.上, 我们可以通过节点的标签(Label) 和Pod的nodeSelector属性的相互匹配,来达到指定的效果。
如图所示: .
从上面的Pod调度的角度看,我们得有-个存储中心,用来存储各节点资源使用情况、健康状态、以及各Pod的基本信息等,这样Pod的调度来能正常进行。
在K8S中,采用etcd组件作为一一个高可用强一致性的存储仓库, 该组件可以内置在K8S中,也可以外部搭建供K8S使用。
集群上的所有配置信息都存储在了etcd, 为了考虑各个组件的相对独立,以及整体的维护性,对于这些存储数据的增、删、改、查,统一由kube-apiserver来进行调用,apiserver 也提供了REST的支持,不仅对各个内部组件提供服务外,还对集群外部用户暴露服务。
外部用户可以通过REST接口,或者kubectl命令行工具进行集群管理,其内在都是与apiserver 进行通信。
如图所示:
前面讲了外部用户如何管理K8S,而我们更关心的是内部运行的Pod如何对外访问。使用过Docker的同学应该知道,如果使用bridge模式,在容器创建时,都会分配一个虚拟IP,该IP外部是没法访问到的,我们需要做一层端口映射, 将容器内端口与宿主机端口进行映射绑定,这样外部通过访问宿主机的指定端口,就可以访问到内部容器端口了。
那么,K8S的外部访问是否也是这样实现的?答案是否定的,K8S中情况要复杂-些。因为上面讲的Docker是单机模式下的,而且一个容器对外就暴露一一个服务。 在分布式集群下,一个服务往往由多个Application 提供,用来分担访问压力,而且这些Application可能会分布在多个节点上,这样又涉及到了跨主机的通信。
这里,K8S引入了Service的概念,将多个相同的Pod包装成一个完整的service对外提供服务,至于获取到这些相同的Pod,每个Pod启动时都会设置labels属性,在Service中我们通过选择器Selector,选择具有相同Name标签属性的Pod,作为整体服务,并将服务信息通过Apiserver存入etcd中,该工作由Service Controller 来完成。同时,每个节点上会启动一个kube-proxy进程,由它来负责服务地址到Pod地址的代理以及负载均衡等工作。
如图所示:
既然知道了服务是由Pod组成的,那么服务的扩容也就意味着Pod的扩容。通俗点讲,就是在需要时将Pod复制多份,在不需要后,将Pod缩减至指定份数。K8S中通过Replication Controller来进行管理,为每个Pod设置一个期望的副本数,当实际副本数与期望不符时,就动态的进行数量调整,以达到期望值。期望数值可以由我们手动更新,或自动扩容代理来完成。
如图所示:
最后,讲一下kube-controller-manager这个进程的作用。我们知道了ectd 是作为集群数据的存储中心,apiserver 是管理数据中心,作为其他进程与数据中心通信的桥梁。而Service Controller、Replication Controller 这些统- -交由 kube-controller-manager来管理,kube-controller-manager 作为一一个守护进程,每个Controller 都是-个控制循环,通过apiserver监视集群的共享状态,并尝试将实际状态与期望不符的进行改变。关于Controller, manager 中还包含了Node节点控制器( Node Controller)、资源配额管控制器( ResourceQuota Controller)、命名空间控制器( Namespace Controller)等。
如图所示:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。