k8s 1.35学习

K8s 1.35学习

默认可以访问外网,访问不了自己想办法。

文章目录

  • [K8s 1.35学习](#K8s 1.35学习)
    • [1. 名词解析](#1. 名词解析)
    • [2. 安装部署](#2. 安装部署)
      • [1. 基本安装](#1. 基本安装)
      • [2. UI界面](#2. UI界面)
    • [3. 练习手册](#3. 练习手册)
      • [1. Container](#1. Container)
      • [2. Pod](#2. Pod)
      • [3. Deployment](#3. Deployment)
      • [4. Service](#4. Service)
        • [1. 先测试service是否有效](#1. 先测试service是否有效)
        • [2. ClusterIP](#2. ClusterIP)
        • [3. NodePort](#3. NodePort)
      • [5. Ingress](#5. Ingress)
      • [6. NameSpace](#6. NameSpace)
      • [7. ConfigMap](#7. ConfigMap)
      • [8. Secret](#8. Secret)
      • [9. Job](#9. Job)
    • [4. 排查手册](#4. 排查手册)
      • [1. service无法访问](#1. service无法访问)
      • [2. 镜像站有问题](#2. 镜像站有问题)
      • [3. 检查yaml格式](#3. 检查yaml格式)
    • 参考

1. 名词解析

核心概念

Docker:一个完整的容器平台,提供构建、管理、运行容器的功能。

containerd:一个轻量级的容器运行时,专注于容器的生命周期管理,通常用于后台服务(如 Kubernetes)。

Kubernetes (K8s):容器编排平台,自动化部署、扩展和管理容器化应用。

container(容器) :本质是进程,而 pod是管理这一组进程的资源。

Kubernetes 基础架构组件

Pod:K8s 中最小的部署单元,包含一个或多个容器,运行在同一个节点上。

Node:K8s 集群中的工作节点,运行容器和 Pod。包括主节点和工作节点。

Cluster:由多个节点组成,提供应用运行环境。

Kubelet:每个节点上的代理,负责管理本节点上的 Pod 和容器

kubeadm:快速启动集群的工具。

kubectl:命令行工具,用于管理集群。

Kube-Proxy:负责服务的网络代理,处理流量转发。

配置与存储

ConfigMap:存储配置数据,供容器在运行时使用(不超过1MB)。Namespace划分资源后,数据库地址可能不一样,可以创建不同命名空间的configmap存放DB_URL。configmap和secret可通过环境变量等方式注入到容器。

Secret:存储敏感数据,如mysql密码、API 密钥。

Volume:存储持久化数据,可以挂载到 Pod 中的容器。

pv:PersistentVolume,集群中的物理存储抽象。举个例子,k8s不能直接让pod挂载NFS地址。必须得创建一个pv,在pv定义里写上NFS服务器的地址和路径。Pod 通过 PVC 申请到的是这个 PV,而 pv背后实际挂载的是NFS。

pvc:PersistentVolumeClaim,用户(或 Pod)对 PV 资源的请求/声明。

sc:StorageClass,定义了动态卷供应的"模板",指定了当 PVC 申请存储时,应使用哪个存储提供者、使用哪些参数来创建 PV。

nfs:网络文件系统。nfs、gfs、longhorn 是具体的存储系统或驱动,StorageClass 可以配置为使用这些存储系统来自动地创建 PV。

gfs:GlusterFS,分布式文件系统。

longhorn:一个为k8s设计的分布式块存储系统。

举个例子:

客户 写个申请单 (PVC) ,说要一块"快速SSD"硬盘。自动售货机 (StorageClass) 接到单子,立刻调用 longhorn 这个品牌的生产线,做出一块新的实体硬盘 (PV) 给客户。客户把他的程序 (Pod) 启动,程序就能把需要永久保存的数据,写到这块通过申请单 (PVC) 申请来的硬盘 (Volume) 里了。程序的配置和密码,则分别从记事本 (ConfigMap)保险箱 (Secret) 里读取。

部署与扩展

Helm:K8s 包管理工具,用于管理应用的安装和升级。

CRD (Custom Resource Definition):自定义资源定义,允许用户扩展 K8s API。

Scheduler:负责将未分配的 Pod 分配到合适的节点上。

Etcd:K8s 的一致性存储,用于保存集群的配置和状态。微服务之间通过服务注册中心nacos/etcd互相发现和调用。

开发与构建流程

代码仓库:存放应用程序源码。

CI/CD:持续集成/持续部署流水线。当代码变更时,自动构建、测试并生成容器镜像。

镜像仓库:存储CI/CD构建好的容器镜像,是K8s集群拉取镜像的源头。

Clusters (集群资源)

Namespace:用于划分集群资源(如dev,test,uat,prod),支持多租户和隔离。

Node:K8s 集群中的工作节点,运行容器和 Pod。包括主节点和工作节点。

Workloads (工作负载)

Pods:K8s 中最小的部署单元,包含一个或多个容器,运行在同一个节点上。

Deployment:定义应用如何更新和扩展,确保指定数量的 Pod 副本在任何时候都在运行。

StatefulSet:用于管理有状态应用,保证 Pod 的唯一性和稳定性。

DaemonSet:确保每个节点上都有一个 Pod 副本,通常用于日志、监控等服务。

ReplicaSet:确保某个 Pod 数量始终保持一致,通常与 Deployment 配合使用。

Job:用于批量任务的控制器,保证一定数量的 Pod 执行完任务。

CronJob:定时任务,类似于 Linux 的 cron。

Network (网络)

Service:为 Pod 提供稳定的访问接口,负载均衡流量。每个Service背后对应一组Pod(容器组),K8s的Service实现负载均衡和服务发现。Service NodePort是四层转发(只认端口,不认内容)。

Ingress:根据定义的规则,将外部到达的http/https请求转发到集群内部对应的Service。Ingress是七层转发(认域名、认路径、认 Cookie、认 Header)。

其它

常见流量流向:用户-> 负载均衡器 -> Ingress Controller(Ingress规则执行者,如nginx,HAProxy等) -> Ingress规则 -> Service -> Pod (微服务实例)

SkyWalking:用于链路追踪,用于监控和分析单个请求在微服务之间调用的完整路径。

EFK:日志体系,Fluentd/Fluent Bit作为日志采集代理,部署在每个节点上,收集容器和日志系统。ES作为日志的存储和索引引擎。kibana提供强大的日志查询、分析和可视化界面。

ELK:一般用logstash做日志采集。

常见监控告警体系:Prometheus负责抓取和存储来自所有服务、节点和k8s组件的监控指标。Grafana从Prometheus读取数据,并以仪表盘进行可视化展示。AlertManager处理有Prometheus根据规则触发的警报,并通过邮件等渠道发送告警通知。

zookeeper:一个分布式协调服务的中间件,常用于注册中心,配置管理,选主节点,分布式锁。

kafka:一个分布式流处理平台,常用于消息队列,流处理,日志收集(如filebeat->kafka->logstash->es),事件溯源。在2.8.0之前依赖zookeeper来管理元数据。

harbor:私有容器镜像仓库,可理解为企业内部的docker hub。

2. 安装部署

master: ubuntu 24 live server, 192.168.201.134

node1: ubuntu 24 live server, 192.168.201.135

命令行工具:mobaxterm

1. 基本安装

两台机子都执行以下操作

关闭 swap:Kubernetes 要求关闭交换分区,因为它会干扰内存管理和 Pod 调度。

bash 复制代码
# 关闭防火墙 (生产环境建议按需开放端口)
sudo ufw disable

sudo swapoff -a
sudo sed -i '/ swap / s/^/#/' /etc/fstab
sudo sed -i '/swap/d' /etc/fstab

# 设置主机名 (方便区分)<!--citation:2-->
Master 执行: sudo hostnamectl set-hostname k8s-master
Worker 执行: sudo hostnamectl set-hostname k8s-node1

# 修改 /etc/hosts 映射
cat <<EOF | sudo tee -a /etc/hosts
192.168.201.134 k8s-master
192.168.201.135 k8s-node1
EOF

配置内核参数:加载必要的网络模块。

bash 复制代码
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilter

配置网络转发

bash 复制代码
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF
sudo sysctl --system

#sudo iptables -L FORWARD
#Chain FORWARD (policy DROP) 
#如果是drop则所有跨接口的数据包被丢弃无法完成流量转发
#Pod → Service ClusterIP → DNAT(rule by kube-proxy) → Pod IP
#sudo iptables -P FORWARD ACCEPT
#临时改成accept

安装Containerd

复制代码
sudo apt-get update
sudo apt-get install -y containerd

生成默认配置并启用 Systemd Cgroup。

bash 复制代码
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
#生成 Containerd 的默认配置文件,并保存
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/g' /etc/containerd/config.toml
#这样 Containerd 就能和 systemd 的 cgroup 驱动配合工作
sudo systemctl restart containerd
sudo systemctl enable containerd

安装 Kubeadm、Kubelet、Kubectl

bash 复制代码
sudo apt-get install -y apt-transport-https ca-certificates curl

curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.35/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
#下载并导入 Kubernetes 的 GPG 密钥,用于验证软件包签名。

echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.35/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
#添加软件源地址

sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
# 锁定版本防止自动升级

重启两台虚拟机

初始化master节点(仅在192.168.201.134执行)

bash 复制代码
sudo kubeadm init \
  --apiserver-advertise-address=192.168.201.134 \
  --node-name=k8s-master \
  --pod-network-cidr=10.244.0.0/16 \
  --kubernetes-version v1.35.1 \
  --image-repository=registry.aliyuncs.com/google_containers
#初始化一个新的k8s控制平面节点
#指定api服务器的监听地址
#指定节点名称
#为Pod网络分配IP地址范围
#使用阿里云镜像源

echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bashrc
source ~/.bashrc

#初始化成功后,按照提示执行以下命令配置kubectl(仅在master执行)
test@test:~$ mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
#修改文件所有者为你自己,这样你就可以用普通用户身份使用 kubectl。

保存输出的kubeadm join命令,用于节点加入。

安装网络插件flannel(仅在 Master 执行)

flannel为 Pod 提供网络通信

bash 复制代码
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml

加入worker节点(仅在192.168.201.135执行)

执行上面保存的kubeadm join

bash 复制代码
scp root@192.168.201.134:/etc/kubernetes/admin.conf /etc/kubernetes/admin.conf
echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bashrc
source ~/.bashrc
kubectl config view

kubeadm join 192.168.201.134:6443 --token az8s0w.20d9oka2twwhzph1 --discovery-token-ca-cert-hash sha256:2732325cc26d1d854a1c9784f28304c6f902785099b51e9eb86eff4a38cc82db --node-name=k8s-node1 

#如果失败,先重置一下状态,再获取新token,再加入
node1执行 sudo kubeadm reset -f
master执行 kubeadm token create --print-join-command

#--ignore-preflight-errors=all

等一会儿,验证集群,在master节点执行

复制代码
kubectl get nodes -w

以下问题有可能发生。由于Flannel接管网络后,只保留了pod网段和docker网桥的路由,将默认路由给删了,所以要手动加回去???

两台机子执行

bash 复制代码
ip route show
# 添加默认路由
sudo ip route add default via 192.168.201.2 dev ens33

2. UI界面

在 Master 节点执行

下载安装helm

bash 复制代码
sudo apt-get install curl gpg apt-transport-https --yes
curl -fsSL https://packages.buildkite.com/helm-linux/helm-debian/gpgkey | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg > /dev/null
echo "deb [signed-by=/usr/share/keyrings/helm.gpg] https://packages.buildkite.com/helm-linux/helm-debian/any/ any main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list
sudo apt-get update
sudo apt-get install helm
bash 复制代码
helm repo add headlamp https://kubernetes-sigs.github.io/headlamp/
helm install my-headlamp headlamp/headlamp --namespace kube-system

kubectl get pods -n kube-system -l app.kubernetes.io/name=headlamp

kubectl get svc -n kube-system | grep headlamp
#my-headlamp   ClusterIP 10.101.189.86 <none> 80/TCP
#查看服务名称

kubectl patch svc my-headlamp -n kube-system -p '{"spec": {"type": "NodePort"}}'
#暴露服务

kubectl get svc -n kube-system | grep headlamp
#my-headlamp  NodePort 10.101.189.86 80:30809/TCP
#找到对应服务的网址

# 1. 创建管理员账号
kubectl -n kube-system create serviceaccount headlamp-admin

# 2. 给账号绑定权限
kubectl create clusterrolebinding headlamp-admin --serviceaccount=kube-system:headlamp-admin --clusterrole=cluster-admin

# 3. 获取登录 Token(复制输出的长字符串)
# token会过期,设置10年有效期
kubectl create token headlamp-admin -n kube-system --duration=87600h
#eyJhbGciOiJSUzI1NiIsImtpZCI6Inc1Z3Fjajg5bWhQbTgyYXZWY2M0NVpJWUM5WU9VcVM4TmcyR2RzLVEzeGMifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoyMDg2NDA3NTA1LCJpYXQiOjE3NzEwNDc1MDUsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwianRpIjoiZGVlMDVlZGQtOWY2Yi00ZWVjLTkyNGQtOTM5YzU1ZDEwYzg5Iiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsInNlcnZpY2VhY2NvdW50Ijp7Im5hbWUiOiJoZWFkbGFtcC1hZG1pbiIsInVpZCI6IjZkMWVlOTVmLTllMDYtNDA0MC1hZjY5LTM5ZjA3Mjg1YTk2OCJ9fSwibmJmIjoxNzcxMDQ3NTA1LCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06aGVhZGxhbXAtYWRtaW4ifQ.Tyu-vkOMQ-V41pKAf3lhvegjJwx4go9CjKLuZQB90QVNhEGSZa-QvEV0gfK53dP9ebarU0oTubem56KR6uwbf6zkUzVtJoH6zs0QvFPH4KyNItW-1igtYB-y3QatLIP55QKe2gnQXLQylKjeM24K7mzhy5X_nKLOCUvZU3UJ23bTT-VpWZQ-ZkcKQ8r2fP_3w2fbEyTq2gnNSNn643CjDgeeQb2DviWbQKyQPgQZdYf3VpqtQGfRxTd75SYvppPDhP2NFqfWA8QdveEX6gY-d-Dm9WbeSGcQwNtA-wCfDN60muadUv2USg4HedOe1xvT8BKq9__7JqeFNEhSYnbxUw

访问网址,粘贴token

http://192.168.201.134:30809

3. 练习手册

Kubernetes 练习手册

1. Container

go 复制代码
root@test:/home/test/k8s# nano main.go

package main

import (
	"io"
	"net/http"
)

func hello(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, "[v1] Hello, Kubernetes!")
}

func main() {
	http.HandleFunc("/", hello)
	http.ListenAndServe(":3000", nil)
}
dockerfile 复制代码
# Dockerfile
nano Dockerfile

FROM golang:1.16-buster AS builder
RUN mkdir /src
ADD . /src
WORKDIR /src

RUN go env -w GO111MODULE=auto
RUN go build -o main .

FROM gcr.io/distroless/base-debian10

WORKDIR /

COPY --from=builder /src/main /main
EXPOSE 3000
ENTRYPOINT ["/main"]

k8s安装后,之前下的docker会消失,得重新下载

bash 复制代码
# 安装 Docker
sudo apt-get update
sudo apt-get install -y docker.io

# 让 Docker 使用 containerd 作为运行时
# 编辑 Docker 配置文件
sudo nano /etc/docker/daemon.json
# 添加以下内容
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2"
}
# 重启 Docker
sudo systemctl start docker
sudo systemctl enable docker

xxx为自己的dockerhub仓库名

bash 复制代码
#打包成镜像
root@test:/home/test/k8s# docker build . -t cllsse/hellok8s:v1
docker images
#docker run -p 3000:3000 --name hellok8s -d cllsse/hellok8s:v1

docker login -u cllsse
docker push cllsse/hellok8s:v1
#推送到dockerhub中

2. Pod

Pod 是我们将要创建的第一个 k8s 资源,也是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。

写一个可以创建nginx的pod

yaml 复制代码
# nginx.yaml
nano nginx.yaml

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
spec:
  containers:
    - name: nginx-container
      image: nginx

其中 kind 表示我们要创建的资源是 Pod 类型, metadata.name 表示要创建的 pod 的名字,这个名字需要是唯一的。 spec.containers 表示要运行的容器的名称和镜像名称。镜像默认来源 DockerHub

bash 复制代码
kubectl apply -f nginx.yaml
#创建pod
kubectl get pods
#NAME        READY   STATUS              RESTARTS   AGE
#nginx-pod   0/1     ContainerCreating   0          5s

kubectl port-forward nginx-pod 4000:80
#将nginx的80端口映射到本机4000端口

kubectl exec -it nginx-pod -- /bin/bash
# 进入Pod内容器的shell
echo "hello kubernetes by nginx!" > /usr/share/nginx/html/index.html
exit

curl http://127.0.0.1:4000/
#hello kubernetes by nginx!

#kubectl logs  nginx-pod
#kubectl delete pod nginx-pod
# pod "nginx" deleted

#kubectl delete -f nginx.yaml
# pod "nginx" deleted

一个pod可以管理多个container

hellok8s:v1的pod的资源文件

yaml 复制代码
# hellok8s.yaml
cat << EOF > hellok8s.yaml
apiVersion: v1
kind: Pod
metadata:
  name: hellok8s
spec:
  containers:
    - name: hellok8s-container
      image: guangzhengli/hellok8s:v1
EOF
复制代码
kubectl apply -f hellok8s.yaml
kubectl get pods
kubectl port-forward hellok8s 3001:3000

#netstat -tulpn | grep :3001
#kill -9 进程号

3. Deployment

Deployment是部署和管理标准、可扩展的无状态应用的首选方式,可通过声明的方式实现应用的自动部署、版本升级、扩缩容和更新回滚。

当手动删除一个 pod 资源后,deployment 会自动创建一个新的 pod。所以当我们管理成千上万的pod时,只用维护deployment.yaml的定义就行。

实现扩容,比如从三个副本扩到五个副本。

yaml 复制代码
cat << EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hellok8s-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hellok8s
  template:
    metadata:
      labels:
        app: hellok8s
    spec:
      containers:
        - image: guangzhengli/hellok8s:v1
          name: hellok8s-container
EOF

其中 kind 表示我们要创建的资源是 deployment 类型, metadata.name 表示要创建的 deployment 的名字,这个名字需要是唯一的。

spec 里面表示,首先 replicas 表示的是部署的 pod 副本数量,selector 里面表示的是 deployment 资源和 pod 资源关联的方式,这里表示 deployment 会管理 (selector) 所有 labels=app: hellok8s 的 pod。

template 的内容是用来定义 pod 资源的,你会发现和作业一:Hellok8s Pod 资源的定义是差不多的,唯一的区别是我们需要加上 metadata.labels 来和上面的 selector.matchLabels 对应起来。来表明 pod 是被 deployment 管理,不用在template 里面加上 metadata.name 是因为 deployment 会主动为我们创建 pod 的唯一name

每次创建的 pod 名称都会变化,某些命令记得替换成你的 pod 的名称

bash 复制代码
kubectl apply -f deployment.yaml
#创建或更新1个deployment资源
kubectl get deployments
#NAME             READY   UP-TO-DATE   AVAILABLE   AGE
# hellok8s-deployment   3/3     3            3           5s
kubectl get pods             
#NAME                                   READY   STATUS    RESTARTS   AGE
#hellok8s-deployment-785956f57b-2cq66   1/1     Running   0          34s
#hellok8s-deployment-785956f57b-5c6pv   1/1     Running   0          34s
#hellok8s-deployment-785956f57b-vt4vm   1/1     Running   0          34s

kubectl delete pod hellok8s-deployment-785956f57b-2cq66
kubectl get pods    
#NAME                                   READY   STATUS    RESTARTS   AGE
#hellok8s-deployment-785956f57b-4n954   1/1     Running   0          5s
#hellok8s-deployment-785956f57b-5c6pv   1/1     Running   0          51s
#hellok8s-deployment-785956f57b-vt4vm   1/1     Running   0          51s

当手动删除一个 pod 资源后,deployment 会自动创建一个新的 pod。所以当我们管理成千上万的pod时,只用维护deployment.yaml的定义就行。

如果我们想要自动扩容成5个副本只需将replicas的值设置成5,然后kubectl apply -f deployment.yaml

同理,如果我们想要自动升级,只需把v1改成v2,然后kubectl apply -f deployment.yaml

bash 复制代码
kubectl rollout history deployment hellok8s-deployment
#查看历史版本

kubectl rollout undo deployment/hellok8s-deployment --to-revision=2
#版本回滚
#kubectl describe pod hellok8s-deployment-77bffb88c5-cvm5c

实现滚动更新

RollingUpdate: 逐渐增加新版本的 pod,逐渐减少旧版本的 pod。

Recreate: 在新版本的 pod 增加前,先将所有旧版本 pod 删除。

maxSurge:最大峰值,用来指定可以创建的超出期望 Pod 个数的 Pod 数量。

maxUnavailable:最大不可用,用来指定更新过程中不可用的 Pod 的个数上限。

以下参数配置意味着最大可能会创建 4 个 hellok8s pod (replicas + maxSurge),最小会有 2 个 hellok8s pod 存活 (replicas - maxUnavailable)。

yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hellok8s-deployment
spec:
  strategy:
     rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
  replicas: 3
  selector:
    matchLabels:
      app: hellok8s
  template:
    metadata:
      labels:
        app: hellok8s
    spec:
      containers:
      - image: guangzhengli/hellok8s:v2
        name: hellok8s-container

4. Service

前面使用了port-forward将pod端口暴露到本地,一旦deployment重新创建pod,pod的名字和ip地址也会随之变化,如何稳定保证的访问地址?

k8s提供了一种名叫Service的资源来帮助解决这些问题,它为 pod 提供一个稳定的 Endpoint。Service 位于 pod 的前面,负责接收请求并将它们传递给它后面的所有pod。一旦服务中的 Pod 集合发生更改,Endpoints 就会被更新,请求的重定向自然也会导向最新的 pod。

Kubernetes ServiceTypes 允许指定你所需要的 Service 类型,默认是 ClusterIPType 的值包括如下:

  • ClusterIP:通过集群的内部 IP 暴露服务,选择该值时服务只能够在集群内部访问。 这也是默认的 ServiceType
  • NodePort:通过每个节点上的 IP 和静态端口(NodePort)暴露服务。 NodePort 服务会路由到自动创建的 ClusterIP 服务。 通过请求 <节点 IP>:<节点端口>,你可以从集群的外部访问一个 NodePort 服务。
  • LoadBalancer:使用云提供商的负载均衡器向外部暴露服务。 外部负载均衡器可以将流量路由到自动创建的 NodePort 服务和 ClusterIP 服务上。
  • ExternalName:通过返回 CNAME 和对应值,可以将服务映射到 externalName 字段的内容(例如,foo.bar.example.com)。 无需创建任何类型代理。
1. 先测试service是否有效

service无效建议删掉虚拟机,从0开始

yaml 复制代码
rm web-test.yaml
nano web-test.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-server
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web-server
  template:
    metadata:
      labels:
        app: web-server
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        ports:
        - containerPort: 80
        # 启动时自动把主机名写入 nginx 首页
        command: ["/bin/sh", "-c", "echo \"Hello from $(hostname)\" > /usr/share/nginx/html/index.html && nginx -g 'daemon off;'"]
---
apiVersion: v1
kind: Service
metadata:
  name: web-service
spec:
  selector:
    app: web-server
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: ClusterIP
bash 复制代码
kubectl apply -f web-test.yaml

root@test:~# kubectl get pods -l app=web-server -o wide
NAME                          READY   STATUS    RESTARTS   AGE   IP           NODE        NOMINATED NODE   READINESS GATES
web-server-598ddf44df-8pcsr   1/1     Running   0          70s   10.244.1.2   k8s-node1   <none>           <none>
web-server-598ddf44df-g58mf   1/1     Running   0          70s   10.244.1.4   k8s-node1   <none>           <none>
web-server-598ddf44df-kfblv   1/1     Running   0          70s   10.244.1.3   k8s-node1   <none>           <none>

root@test:~# kubectl get svc web-service
NAME          TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
web-service   ClusterIP   10.107.178.172   <none>        80/TCP    101s

kubectl run client-pod --rm -it --image=alpine/curl -- sh
/ # curl 10.107.178.172
Hello from web-server-598ddf44df-8pcsr
2. ClusterIP

仅集群内可访问service

dockerfile 复制代码
rm Dockerfile
nano Dockerfile

# Dockerfile
FROM golang:1.16-buster AS builder
RUN mkdir /src
ADD . /src
WORKDIR /src

RUN go env -w GO111MODULE=auto
RUN go build -o main .

FROM gcr.io/distroless/base-debian10

WORKDIR /

COPY --from=builder /src/main /main
EXPOSE 3000
ENTRYPOINT ["/main"]



# 备用dockerfile
FROM golang:1.21-alpine AS builder

WORKDIR /app

# 先创建 go.mod 文件(如果不存在)
RUN if [ ! -f go.mod ]; then \
    go mod init hellok8s && \
    echo "module hellok8s" > go.mod && \
    echo "go 1.21" >> go.mod; \
    fi

# 复制源代码
COPY main.go .

# 编译应用
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o main .

# 使用 Alpine 作为运行时(可以进入命令行)
FROM alpine/curl

WORKDIR /app

# 从构建阶段复制二进制文件
COPY --from=builder /app/main .

# 创建非 root 用户
RUN addgroup -g 1000 appuser && \
    adduser -u 1000 -G appuser -s /bin/bash -D appuser && \
    chown -R appuser:appuser /app
USER appuser

# 暴露端口
EXPOSE 3000

# 运行应用
CMD ["./main"]

以下是hellok8s:v3版本

go 复制代码
rm main.go
nano main.go

package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func hello(w http.ResponseWriter, r *http.Request) {
	host, _ := os.Hostname()
	io.WriteString(w, fmt.Sprintf("[v3] Hello, Kubernetes!, From host: %s", host))
}

func main() {
	http.HandleFunc("/", hello)
	http.ListenAndServe(":3000", nil)
}
bash 复制代码
#打包成镜像
apt  install docker.io
docker login -u cllsse
docker build . -t cllsse/hellok8s:v3
docker images
#docker run -p 3000:3000 --name hellok8s -d cllsse/hellok8s:v3
docker push cllsse/hellok8s:v3

修改deployment为v3版本

yaml 复制代码
rm deployment.yaml
cat << EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hellok8s-v3
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hellok8s
  template:
    metadata:
      labels:
        app: hellok8s
    spec:
      containers:
      - name: hellok8s
        image: cllsse/hellok8s:v3
        ports:
        - containerPort: 3000
EOF

更新deployment

复制代码
kubectl apply -f deployment.yaml

接下来是 Service 资源的定义,我们使用 ClusterIP (默认)的方式定义 Service,通过 kubernetes 集群的内部 IP 暴露服务,当我们只需要让集群中运行的其他应用程序访问我们的 pod 时,就可以使用这种类型的Service。首先创建一个 service-hellok8s-clusterip.yaml 文件。

bash 复制代码
rm service-hellok8s-clusterip.yaml
cat << EOF > service-hellok8s-clusterip.yaml
apiVersion: v1
kind: Service
metadata:
  name: hellok8s-svc
spec:
  selector:
    app: hellok8s
  ports:
    - protocol: TCP   # protocol别忘了
      port: 80         # Service 暴露的端口
      targetPort: 3000  # 对应 Go 程序监听的端口
  type: ClusterIP
EOF

首先通过 kubectl get endpoints 来看看 Endpoint。被 selector 选中的 Pod,就称为 Service 的 Endpoints。它维护着 Pod 的 IP 地址,只要服务中的 Pod 集合发生更改,Endpoints 就会被更新。通过 kubectl get pod -o wide 命令获取 Pod 更多的信息,可以看到 3 个 Pod 的 IP 地址和 Endpoints 中是保持一致的,你可以试试增大或减少 Deployment 中 Pod 的 replicas,观察 Endpoints 会不会发生变化。

bash 复制代码
kubectl apply -f service-hellok8s-clusterip.yaml

kubectl get endpoints
NAME           ENDPOINTS                                         AGE
hellok8s-svc   10.244.1.7:3000,10.244.1.8:3000,10.244.1.9:3000   8s
kubernetes     192.168.201.134:6443                              62m
web-service    10.244.1.2:80,10.244.1.3:80,10.244.1.4:80         26m

kubectl get pod -o wide
NAME                           READY   STATUS    RESTARTS   AGE   IP           NODE        NOMINATED NODE   READINESS GATES
hellok8s-v3-67bbd8b8c5-557c8   1/1     Running   0          55s   10.244.1.9   k8s-node1   <none>           <none>
hellok8s-v3-67bbd8b8c5-w5vjt   1/1     Running   0          55s   10.244.1.8   k8s-node1   <none>           <none>
hellok8s-v3-67bbd8b8c5-xqzmd   1/1     Running   0          55s   10.244.1.7   k8s-node1   <none>           <none>
web-server-598ddf44df-8pcsr    1/1     Running   0          27m   10.244.1.2   k8s-node1   <none>           <none>
web-server-598ddf44df-g58mf    1/1     Running   0          27m   10.244.1.4   k8s-node1   <none>           <none>
web-server-598ddf44df-kfblv    1/1     Running   0          27m   10.244.1.3   k8s-node1   <none>           <none>


kubectl get service
NAME           TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
hellok8s-svc   ClusterIP   10.97.124.216    <none>        80/TCP    47s
kubernetes     ClusterIP   10.96.0.1        <none>        443/TCP   62m
web-service    ClusterIP   10.107.178.172   <none>        80/TCP    27m

接着我们可以通过在集群其它应用中访问服务 hellok8s-svc 的 IP 地址 10.97.124.216 来访问 hellok8s:v3 服务。

这里通过在集群内创建一个 nginx 来访问 hellok8s 服务。创建后进入 nginx 容器来用 curl 命令访问 service-hellok8s-clusterip

yaml 复制代码
#nano nginx.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  containers:
    - name: nginx-container
      image: nginx
bash 复制代码
kubectl apply -f nginx.yaml
kubectl get pods

kubectl get service
#NAME           TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
#hellok8s-svc   ClusterIP   10.97.124.216    <none>        80/TCP    106s
#kubernetes     ClusterIP   10.96.0.1        <none>        443/TCP   63m
#web-service    ClusterIP   10.107.178.172   <none>        80/TCP    28m

kubectl exec -it nginx -- /bin/bash
root@nginx:/# curl 10.97.124.216:80
[v3] Hello, Kubernetes!, From host: hellok8s-v3-67bbd8b8c5-w5vjtroot@nginx:/# curl 10.97.124.216:80
[v3] Hello, Kubernetes!, From host: hellok8s-v3-67bbd8b8c5-xqzmdroot@nginx:/# curl 10.97.124.216:80
[v3] Hello, Kubernetes!, From host: hellok8s-v3-67bbd8b8c5-xqzmdroot@nginx:/# curl 10.97.124.216:80
[v3] Hello, Kubernetes!, From host: hellok8s-v3-67bbd8b8c5-xqzmdroot@nginx:/# curl 10.97.124.216:80
[v3] Hello, Kubernetes!, From host: hellok8s-v3-67bbd8b8c5-557c8root@nginx:/#

可以看到,我们多次 curl 10.97.124.216:80 访问 hellok8s Service IP 地址,返回的 hellok8s:v3 hostname 不一样,说明 Service 可以接收请求并将它们传递给它后面的所有 pod,还可以自动负载均衡。你也可以试试增加或者减少 hellok8s:v3 pod 副本数量,观察 Service 的请求是否会动态变更。调用过程如下图所示:

3. NodePort

我们知道kubernetes 集群并不是单机运行,它管理着多台节点即 Node,可以通过每个节点上的 IP 和静态端口(NodePort)暴露服务。如下图所示,如果集群内有两台 Node 运行着 hellok8s:v3,我们创建一个 NodePort 类型的 Service,将 hellok8s:v33000 端口映射到 Node 机器的 30000 端口 (在 30000-32767 范围内),就可以通过访问 http://node1-ip:30000 或者 http://node2-ip:30000 访问到服务。

yaml 复制代码
rm hellok8s-nodeport.yaml
cat << EOF >  hellok8s-nodeport.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hellok8s-nodeport
spec:
  replicas: 2
  selector:
    matchLabels:
      app: hello-nodeport
  template:
    metadata:
      labels:
        app: hello-nodeport
    spec:
      containers:
      - name: hellok8s
        image: cllsse/hellok8s:v3
        ports:
        - containerPort: 3000
---
apiVersion: v1
kind: Service
metadata:
  name: hello-nodeport-svc
spec:
  type: NodePort
  selector:
    app: hello-nodeport
  ports:
    - protocol: TCP
      port: 80         # 集群内部 ClusterIP 访问的端口
      targetPort: 3000  # 对应容器内的 3000 端口
      nodePort: 30080   # 浏览器/外部访问的端口
EOF
bash 复制代码
kubectl apply -f hellok8s-nodeport.yaml
kubectl get svc hello-nodeport-svc
kubectl get pods -o wide
curl http://192.168.201.134:30080
curl http://192.168.201.135:30080

5. Ingress

Ingress 公开从集群外部到集群内服务的 HTTP 和 HTTPS 路由。 流量路由由 Ingress 资源上定义的规则控制。Ingress 可为 Service 提供外部可访问的 URL、负载均衡流量、 SSL/TLS,以及基于名称的虚拟托管。你必须拥有一个 Ingress 控制器 才能满足 Ingress 的要求。 仅创建 Ingress 资源本身没有任何效果。 Ingress 控制器 通常负责通过负载均衡器来实现 Ingress。

Ingress 可以"简单理解"为服务的网关 Gateway,它是所有流量的入口,经过配置的路由规则,将流量重定向到后端的服务。

举个例子,假设有100个微服务,我们用service nodeport的话得开100个端口,但是用Ingress的话只用开一个端口,比如下文的 80(节点上) 或 31566(外部访问宿主机 http://192.168.201.134:31566/hello)。

安装 Ingress Nginx Controller ,这里用的是ingress-nginx

bash 复制代码
#删除之前创建的deployment,service
kubectl delete deployment,service --all

# 1. 重新下载官方文件,然后替换其中的镜像
rm -f deploy.yaml
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/baremetal/deploy.yaml

# 一键替换所有官方镜像源为 daocloud 代理源
sed -i 's|registry.k8s.io|k8s.m.daocloud.io|g' deploy.yaml

# 替换主控制器镜像 (v1.11.2 是目前 K8s 1.30+ 最稳定的版本)
sed -i 's|docker.io/liubog2008/ingress-nginx-controller:v1.14.3|dyrnq/ingress-nginx-controller:v1.11.2|g' deploy.yaml

# 替换证书生成器镜像 (admission-create 和 admission-patch 使用同一个)
sed -i 's|docker.io/liubog2008/kube-webhook-certgen:v1.6.7|dyrnq/kube-webhook-certgen:v1.4.1|g' deploy.yaml

# 彻底删除所有的 @sha256 校验码 (这是镜像拉取成功的关键)
sed -i 's|@sha256:[a-z0-9]*||g' deploy.yaml

kubectl apply -f deploy.yaml
kubectl get pods -n ingress-nginx
#NAME                                        READY   STATUS    RESTARTS   AGE
#ingress-nginx-controller-86c8d7b99f-5m8hq   1/1     Running   0          82s

#如果pod启动失败,需要彻底删除
kubectl delete -f deploy.yaml
kubectl get ns ingress-nginx
# 如果还有东西,说明删除不彻底,要继续删
# 开启一个临时代理,以便我们可以直接访问 Kubernetes API
# 执行后这个命令会挂起,请保持这个终端不要关闭,或者在后面加个 & 符号让他后台运行
kubectl proxy &
# 1. 导出 JSON
kubectl get namespace ingress-nginx -o json > tmp.json

# 2. 修改 JSON (利用 sed 删除 spec 里的 finalizers 这一行)
# 注意:我们要把 "finalizers": ["kubernetes"] 变成 "finalizers": []
sed -i 's/"kubernetes"//g' tmp.json
curl -k -H "Content-Type: application/json" -X PUT --data-binary @tmp.json http://127.0.0.1:8001/api/v1/namespaces/ingress-nginx/finalize
kubectl get ns ingress-nginx #应该删掉了

注意:这里的 Service 类型必须是 ClusterIP(默认类型),因为 Ingress 会直接找 Service。

yaml 复制代码
rm hellok8s.yaml
cat << EOF > hellok8s.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hellok8s-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: hellok8s
  template:
    metadata:
      labels:
        app: hellok8s
    spec:
      containers:
      - name: hellok8s
        image: cllsse/hellok8s:v3
        ports:
        - containerPort: 3000
---
apiVersion: v1
kind: Service
metadata:
  name: hellok8s-ingress-svc
spec:
  selector:
    app: hellok8s
  ports:
    - protocol: TCP
      port: 3000
      targetPort: 3000
EOF
yaml 复制代码
rm nginx.yaml
cat << EOF > nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx-container
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-ingress-svc
spec:
  type: ClusterIP
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 4000
      targetPort: 80
EOF
bash 复制代码
kubectl apply -f hellok8s.yaml
kubectl apply -f nginx.yaml
kubectl get pods
kubectl get service

NAME                                   READY   STATUS    RESTARTS   AGE
hellok8s-deployment-67bbd8b8c5-559l5   1/1     Running   0          9m2s
hellok8s-deployment-67bbd8b8c5-bl6p4   1/1     Running   0          9m2s
nginx-deployment-c475b744d-lrkff       1/1     Running   0          12s
nginx-deployment-c475b744d-vng57       1/1     Running   0          55s
NAME                   TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
hellok8s-ingress-svc   ClusterIP   10.99.140.86    <none>        3000/TCP   9m2s
kubernetes             ClusterIP   10.96.0.1       <none>        443/TCP    24m
nginx-ingress-svc      ClusterIP   10.100.24.141   <none>        4000/TCP   55s

下面编写Ingress资源定义,nginx.ingress.kubernetes.io/ssl-redirect: "false" 的意思是这里关闭 https 连接,只使用 http 连接。

匹配前缀为 /hello 的路由规则,重定向到 hellok8s:v3 服务,匹配前缀为 / 的跟路径重定向到 nginx

yaml 复制代码
rm ingress.yaml
nano ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hello-ingress
  annotations:
    # 强制指定,防止某些旧版本控制器不识别 class 字段
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
  # 关键修复:必须指定这个 Class,名字必须是 nginx (可以通过 kubectl get ingressclass 查看)
  ingressClassName: nginx
  rules:
    - http:
        paths:
          - path: /hello
            pathType: Prefix
            backend:
              service:
                name: hellok8s-ingress-svc
                port:
                  number: 3000
          - path: /
            pathType: Prefix
            backend:
              service:
                name: nginx-ingress-svc
                port:
                  number: 4000

我们测试 Ingress 能否把外部流量(比如 80 端口)成功转给 Service 的 3000 或 4000 端口。

bash 复制代码
kubectl apply -f ingress.yaml
kubectl get ingress          
NAME            CLASS   HOSTS   ADDRESS   PORTS   AGE
hello-ingress   nginx   *                 80      7m40s

kubectl get svc -n ingress-nginx
#NAME                                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
#ingress-nginx-controller             NodePort    10.99.205.69    <none>        80:31566/TCP,443:31941/TCP   38m
#ingress-nginx-controller-admission   ClusterIP   10.110.88.186   <none>        443/TCP                      38m

curl http://10.99.205.69/hello
curl http://10.99.205.69/

curl http://192.168.201.134:31566/hello
curl http://192.168.201.134:31566/

成功访问。

6. NameSpace

实际开发我们要把测试,开发,发布等环境区分开来,让不同环境的资源独立,互不影响。这时候就得使用Namespace来帮助隔离资源。

默认使用的命名空间是default

我们尝试创建devtest

bash 复制代码
rm namespace.yaml
cat << EOF > namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: dev
---
apiVersion: v1
kind: Namespace
metadata:
  name: test
EOF
bash 复制代码
kubectl apply -f namespace.yaml
root@test:~# kubectl get namespaces
NAME              STATUS   AGE
default           Active   3h27m
dev               Active   15s
ingress-nginx     Active   70m
kube-flannel      Active   3h21m
kube-node-lease   Active   3h27m
kube-public       Active   3h27m
kube-system       Active   3h27m
test              Active   15s

那么如何在新的 namespace 下创建资源和获取资源呢?只需要在命令后面加上 -n namespace 即可。例如根据上面教程中,在名为 dev 的 namespace 下创建 hellok8s:v3 的 deployment 资源。

bash 复制代码
kubectl apply -f deployment.yaml -n dev
kubectl get pods -n dev

7. ConfigMap

Namespace划分资源后,不同环境下的数据库地址可能不一样,可以创建不同命名空间的configmap存放DB_URL

go 复制代码
rm main.go
nano main.go

package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func hello(w http.ResponseWriter, r *http.Request) {
	host, _ := os.Hostname()
	dbURL := os.Getenv("DB_URL")
	io.WriteString(w, fmt.Sprintf("[v4] Hello, Kubernetes! From host: %s, Get Database Connect URL: %s", host, dbURL))
}

func main() {
	http.HandleFunc("/", hello)
	http.ListenAndServe(":3000", nil)
}

推送至dockerhub,并删除之前创建的所有资源

bash 复制代码
docker build . -t cllsse/hellok8s:v4
docker push cllsse/hellok8s:v4

kubectl delete deployment,service,ingress --all

接下来创建不同 namespace 的 configmap 来存放 DB_URL

创建 hellok8s-config-dev.yaml 文件

bash 复制代码
rm hellok8s-config-dev.yaml
cat << EOF > hellok8s-config-dev.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: hellok8s-config
data:
  DB_URL: "http://DB_ADDRESS_DEV"
EOF

创建 hellok8s-config-test.yaml 文件

bash 复制代码
rm hellok8s-config-test.yaml
cat << EOF > hellok8s-config-test.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: hellok8s-config
data:
  DB_URL: "http://DB_ADDRESS_TEST"
EOF

分别在 dev test 两个 namespace 下创建相同的 ConfigMap,名字都叫 hellok8s-config,但是存放的 Pair 对中 Value 值不一样。

bash 复制代码
kubectl apply -f hellok8s-config-dev.yaml -n dev
kubectl apply -f hellok8s-config-test.yaml -n test 

kubectl get configmap --all-namespaces
NAMESPACE         NAME                                                   DATA   AGE
default           kube-root-ca.crt                                       1      3h40m
dev               hellok8s-config                                        1      7s
dev               kube-root-ca.crt                                       1      13m
ingress-nginx     ingress-nginx-controller                               0      83m
ingress-nginx     kube-root-ca.crt                                       1      83m
kube-flannel      kube-flannel-cfg                                       2      3h34m
kube-flannel      kube-root-ca.crt                                       1      3h34m
kube-node-lease   kube-root-ca.crt                                       1      3h40m
kube-public       cluster-info                                           3      3h40m
kube-public       kube-root-ca.crt                                       1      3h40m
kube-system       coredns                                                1      3h40m
kube-system       extension-apiserver-authentication                     6      3h41m
kube-system       kube-apiserver-legacy-service-account-token-tracking   1      3h41m
kube-system       kube-proxy                                             2      3h40m
kube-system       kube-root-ca.crt                                       1      3h40m
kube-system       kubeadm-config                                         1      3h40m
kube-system       kubelet-config                                         1      3h40m
test              hellok8s-config                                        1      7s
test              kube-root-ca.crt                                       1      13m

接着使用 POD 的方式来部署 hellok8s:v4,其中 env.name 表示的是将 configmap 中的值写进环境变量,这样代码从环境变量中获取 DB_URL,这个 KEY 名称必须保持一致。valueFrom 代表从哪里读取,configMapKeyRef 这里表示从名为 hellok8s-configconfigMap 中读取 KEY=DB_URL 的 Value。

yaml 复制代码
rm hellok8s.yaml
nano hellok8s.yaml

apiVersion: v1
kind: Pod
metadata:
  name: hellok8s-pod
spec:
  containers:
    - name: hellok8s-container
      image: cllsse/hellok8s:v4
      env:
        - name: DB_URL
          valueFrom:
            configMapKeyRef:
              name: hellok8s-config
              key: DB_URL
bash 复制代码
kubectl apply -f hellok8s.yaml -n dev             
kubectl apply -f hellok8s.yaml -n test

kubectl port-forward hellok8s-pod 3000:3000 -n dev

curl http://localhost:3000
# [v4] Hello, Kubernetes! From host: hellok8s-pod, Get Database Connect URL: http://DB_ADDRESS_DEV

kubectl port-forward hellok8s-pod 3000:3000 -n test

curl http://localhost:3000
# [v4] Hello, Kubernetes! From host: hellok8s-pod, Get Database Connect URL: http://DB_ADDRESS_TEST

8. Secret

configmap挂载数据库密码的时候,需要明文挂载,不太安全。

这时候就需要Secret来存储加密信息。虽然在资源文件的编码上,只是通过 Base64 的方式简单编码,但是在实际生产过程中,可以通过 pipeline 或者专业的 AWS KMS 服务进行密钥管理。这样就大大减少了安全事故。

Secret的Value需要base64编码

复制代码
echo "db_password" | base64
# ZGJfcGFzc3dvcmQK

echo "ZGJfcGFzc3dvcmQK" | base64 -d
# db_password
yaml 复制代码
rm hellok8s-secret.yaml
cat << EOF > hellok8s-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: hellok8s-secret
data:
  DB_PASSWORD: "ZGJfcGFzc3dvcmQK"
EOF
yaml 复制代码
rm hellok8s.yaml
cat << EOF > hellok8s.yaml
apiVersion: v1
kind: Pod
metadata:
  name: hellok8s-pod
spec:
  containers:
    - name: hellok8s-container
      image: cllsse/hellok8s:v5
      env:
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: hellok8s-secret
              key: DB_PASSWORD
EOF
go 复制代码
rm main.go
nano main.go

package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func hello(w http.ResponseWriter, r *http.Request) {
	host, _ := os.Hostname()
	dbPassword := os.Getenv("DB_PASSWORD")
	io.WriteString(w, fmt.Sprintf("[v5] Hello, Kubernetes! From host: %s, Get Database Connect Password: %s", host, dbPassword))
}

func main() {
	http.HandleFunc("/", hello)
	http.ListenAndServe(":3000", nil)
}
bash 复制代码
docker build . -t cllsse/hellok8s:v5
docker push cllsse/hellok8s:v5

kubectl apply -f hellok8s-secret.yaml
kubectl apply -f hellok8s.yaml

kubectl port-forward hellok8s-pod 3000:3000
curl http://localhost:3000
#[v5] Hello, Kubernetes! From host: hellok8s-pod, Get Database Connect Password: db_password

9. Job

常见的计算任务,只需要拿到相关数据计算后得出结果即可,无需一直运行。而处理这一类任务的资源就是 Job。

Job 会创建一个或者多个 Pod,并将继续重试 Pod 的执行,直到指定数量的 Pod 成功终止。 随着 Pod 成功结束,Job 跟踪记录成功完成的 Pod 个数。 当数量达到指定的成功个数阈值时,任务(即 Job)结束。 删除 Job 的操作会清除所创建的全部 Pod。 挂起 Job 的操作会删除 Job 的所有活跃 Pod,直到 Job 被再次恢复执行。

下面来看一个 Job 的资源定义,其中 Kind 和 metadata.name 是资源类型和名字就不再解释,completions 指的是会创建 Pod 的数量,每个 pod 都会完成下面的任务。parallelism 指的是并发执行最大数量,例如下面就会先创建 3 个 pod 并发执行任务,一旦某个 pod 执行完成,就会再创建新的 pod 来执行,直到 5 个 pod 执行完成,Job 才会被标记为完成。

restartPolicy = "OnFailure 的含义和 Pod 生命周期相关,Pod 中的容器可能因为退出时返回值非零, 或者容器因为超出内存约束而被杀死等等。 如果发生这类事件,并且 .spec.template.spec.restartPolicy = "OnFailure", Pod 则继续留在当前节点,但容器会被重新运行。因此,你的程序需要能够处理在本地被重启的情况,或者要设置 .spec.template.spec.restartPolicy = "Never"

举个例子:Always就是不管学生是考完了(0)还是晕倒了(非 0),老师都会把他拍醒,让他重考一次

OnFailure就是如果学生顺利交卷(0) :老师就让他回家,不重考了。如果学生中途晕倒(非 0) :老师会把他拍醒,让他在这个考场重考一次

Never就是Never是不管顺利交卷还是中途晕倒都是让他回家,不重考。

yaml 复制代码
rm hello-job.yaml
nano hello-job.yaml

apiVersion: batch/v1
kind: Job
metadata:
  name: hello-job
spec:
  parallelism: 3
  completions: 5
  template:
    spec:
      restartPolicy: OnFailure
      containers:
        - name: echo
          image: busybox
          command:
            - "/bin/sh"
          args:
            - "-c"
            - "for i in 9 8 7 6 5 4 3 2 1 ; do echo $i ; done"

通过下面的命令创建 job,可以通过 kubectl get pods -w 来观察 job 创建 pod 的过程和结果。最后可以通过 logs 命令查看日志。

bash 复制代码
kubectl apply -f hello-job.yaml

kubectl get jobs                  
#NAME        STATUS     COMPLETIONS   DURATION   AGE
#hello-job   Complete   5/5           29s        34s

kubectl get pods                      
#NAME              READY   STATUS      RESTARTS   AGE
#hello-job-2svc6   0/1     Completed   0          61s
#hello-job-knm68   0/1     Completed   0          61s
#hello-job-mtzxj   0/1     Completed   0          61s
#hello-job-wwckl   0/1     Completed   0          43s
#hello-job-znfmp   0/1     Completed   0          44s
#hellok8s-pod      1/1     Running     0          14m

kubectl logs -f hello-job-2svc6

4. 排查手册

1. service无法访问

遇到这个问题建议删掉虚拟机从0开始配。

2. 镜像站有问题

默认能访问外网

复制代码
sudo nano /etc/docker/daemon.json
json 复制代码
{
  "registry-mirrors": [
    "https://docker.m.daocloud.io",
    "https://huecker.io",
    "https://dockerhub.timeweb.cloud",
    "https://noohub.net"
  ]
}
bash 复制代码
sudo systemctl daemon-reload
sudo systemctl restart docker

另外排查yaml中的镜像。

3. 检查yaml格式

bash 复制代码
kubectl apply --dry-run=client -f  xxx.yaml

参考

Kubernetes 练习手册

https://www.processon.com/view/6359fe5f1e08537e2df5be89

https://www.processon.com/view/60599c15f346fb6d9eda1596

https://www.processon.com/view/64a515e8f9b40558f78ff5ff

k8s 流程图模板_ProcessOn思维导图、流程图

相关推荐
三点水-here16 小时前
05 - 大模型推理生产架构设计:混合部署与Kubernetes实战
云原生·容器·kubernetes·hpa·混合架构·gpu调度
别多香了19 小时前
Kubernetes Pod 管理
容器·kubernetes
认真的薛薛21 小时前
3.k8s-暴露pod和service
云原生·容器·kubernetes
人间打气筒(Ada)1 天前
Kubernetes核心技术-service详解
云原生·容器·kubernetes·云计算·devops·service·service代理
切糕师学AI1 天前
Kubernetes Deployment 详解
容器·kubernetes
swbook1 天前
k8s1.35.1二进制部署
docker·kubernetes·k8s·kubectl-ai
运维螺丝钉1 天前
Kubernetes之Istio应用
容器·kubernetes·istio
uNhPiLgvQDpJ1 天前
基于STM32的实验室环境检测系统:温湿度、烟雾、空气质量检测和报警功能
kubernetes
西门吹雪分身1 天前
K8S之Pod生命周期
java·kubernetes·k8s