目录 Kubernetes 的安装和使用(一) Kubernetes 的安装和使用(二) Kubernetes 的安装和使用(三)
k8s 的使用 构建和运行镜像 编写一个 go 程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package mainimport ( "io" "log" "net/http" ) func main () { http.HandleFunc("/" , func (w http.ResponseWriter, r *http.Request) { io.WriteString(w, "[v1] Hello, Kubernetes!" ) }) log.Printf("v1 access http://localhost:3000\n" ) panic (http.ListenAndServe(":3000" , nil )) }
编写 Dockerfile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 FROM golang:1.20 -alpine AS builderWORKDIR /project ADD . . RUN GOPROXY=https://goproxy.cn,direct GOOS=linux GOARCH=amd64 CGO_ENABLED=0 GO111MODULE=auto go build -o main -ldflags "-w -extldflags -static" FROM alpine as prodCOPY --from=builder /project/main . EXPOSE 3000 ENTRYPOINT ["/main" ]
打包镜像
docker build . -t derobukal/hellok8s:v1
执行镜像,并把 3000 端口暴露出来
docker run --rm -p 3000:3000 derobukal/hellok8s:v1
之后可以用 curl 访问 3000 端口,结果正常显示了
1 2 ~ curl 127.0.0.1:3000 [v1] Hello, Kubernetes!%
之后可以把这个镜像推送到镜像仓库
docker login
docker push derobukal/hellok8s:v1
使用 Pod 编写 pod.yaml
1 2 3 4 5 6 7 8 9 10 11 apiVersion: v1 kind: Pod metadata: name: go-http labels: app: go version: v1 spec: containers: - name: go-http image: derobukal/hellok8s:v1
之后创建 pod
1 2 3 4 5 ~ kc apply -f pod.yaml pod/go-http created ~ kc get pods NAME READY STATUS RESTARTS AGE go-http 1/1 Running 0 65s
然后临时开启端口转发,就可以访问相应的服务了
1 2 3 4 5 6 ~ kc port-forward go-http 3000:3000 Forwarding from 127.0.0.1:3000 -> 3000 Forwarding from [::1]:3000 -> 3000 ~ curl http://127.0.0.1:3000 [v1] Hello, Kubernetes!%
在进行以上测试的时候,如果出现 pod 启动不了的情况,可能是因为防火墙的原因,可以开启网络代理之后再试。
使用 Deployment 一般来说,pod 不会被直接的使用,而是用 Deployment 来进行相关的操作。
编写 deployment.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 apiVersion: apps/v1 kind: Deployment metadata: name: hellok8s-go-http spec: replicas: 2 selector: matchLabels: app: hellok8s template: metadata: labels: app: hellok8s spec: containers: - image: derobukal/hellok8s:v1 name: hellok8s
部署 deployment
1 2 3 4 5 ~ kc apply -f deployment.yaml deployment.apps/hellok8s-go-http created ~ kc get deployments NAME READY UP-TO-DATE AVAILABLE AGE hellok8s-go-http 2/2 2 2 79s
kc get pod -o wide 可以查看更详细的 pod 信息。我们可以把配置中的副本数改为 3,之后重新执行部署命令,然后查看详细的 pod 信息如下,可以看到又新增了一个 pod
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
go-http 1/1 Running 0 14m 10.244.0.6 minikube <none> <none>
hellok8s-go-http-6db476b8cb-4n2nx 1/1 Running 0 4m35s 10.244.0.7 minikube <none> <none>
hellok8s-go-http-6db476b8cb-s76jr 1/1 Running 0 4m35s 10.244.0.8 minikube <none> <none>
hellok8s-go-http-6db476b8cb-tjqs9 1/1 Running 0 8s 10.244.0.9 minikube <none> <none>
我们选取任意一个 pod 进行端口转发,随后请求可以看到结果正常
1 2 3 4 ~ kc port-forward hellok8s-go-http-6db476b8cb-4n2nx 3000:3000 Forwarding from 127.0.0.1:3000 -> 3000 Forwarding from [::1]:3000 -> 3000 Handling connection for 3000
更新 deployment 我们将 golang 程序中的 v1 修改为 v2,之后打包新版本镜像并上传
docker build . -t derobukal/hellok8s:v2
docker push derobukal/hellok8s:v2
之后我们修改 deployment.yaml 中的镜像为 derobukal/hellok8s:v2,然后更新部署
1 2 ~ kc apply -f deployment.yaml deployment.apps/hellok8s-go-http configured
可以看到 pod 都重新部署了
1 2 3 4 5 6 ~ kc get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES go-http 1/1 Running 0 25m 10.244.0.6 minikube <none> <none> hellok8s-go-http-8b44d58c5-5bmx7 1/1 Running 0 34s 10.244.0.12 minikube <none> <none> hellok8s-go-http-8b44d58c5-djfcd 1/1 Running 0 35s 10.244.0.11 minikube <none> <none> hellok8s-go-http-8b44d58c5-rt29z 1/1 Running 0 58s 10.244.0.10 minikube <none> <none>
之后选取一个 Pod 进行端口转发,并请求发现返回结果发生了变化
1 2 3 4 5 6 7 ~ kc port-forward hellok8s-go-http-8b44d58c5-5bmx7 3000:3000 Forwarding from 127.0.0.1:3000 -> 3000 Forwarding from [::1]:3000 -> 3000 Handling connection for 3000 ~ curl http://127.0.0.1:3000 [v2] Hello, Kubernetes!%
回滚 deployment 查看版本信息
1 2 3 4 5 ~ kc rollout history deployment/hellok8s-go-http deployment.apps/hellok8s-go-http REVISION CHANGE-CAUSE 1 <none> 2 <none>
查看具体版本 2
1 2 3 4 5 6 7 8 9 10 11 12 13 ~ kc rollout history deployment/hellok8s-go-http --revision=2 deployment.apps/hellok8s-go-http with revision Pod Template: Labels: app=hellok8s pod-template-hash=8b44d58c5 Containers: hellok8s: Image: derobukal/hellok8s:v2 Port: <none> Host Port: <none> Environment: <none> Mounts: <none> Volumes: <none>
查看具体版本 1
1 2 3 4 5 6 7 8 9 10 11 12 13 ~ kc rollout history deployment/hellok8s-go-http --revision=1 deployment.apps/hellok8s-go-http with revision Pod Template: Labels: app=hellok8s pod-template-hash=6db476b8cb Containers: hellok8s: Image: derobukal/hellok8s:v1 Port: <none> Host Port: <none> Environment: <none> Mounts: <none> Volumes: <none>
回退到版本 1
1 2 ~ kc rollout undo deployment/hellok8s-go-http --to-revision=1 deployment.apps/hellok8s-go-http rolled back
此时查看 pod 可以发现 pod 已经发生了改变,访问服务返回的也是 v1 版本信息了。
部署失败 我们构建一个如下的程序
1 2 3 4 5 package mainfunc main () { panic ("something went wrong" ) }
之后打包一个新版本镜像:docker build . -t derobukal/hellok8s:v_error 并对这个镜像进行 push:docker push derobukal/hellok8s:v_error。
之后可以简单地使用命令而不修改 deployment.yaml 文件来重新部署 deployment,通过命令修改镜像:
1 2 3 4 5 6 7 8 9 ~ kc set image deployment/hellok8s-go-http hellok8s=derobukal/hellok8s:v2_error deployment.apps/hellok8s-go-http image updated ~ kc get pods NAME READY STATUS RESTARTS AGE go-http 1/1 Running 1 (7m34s ago) 54m hellok8s-go-http-55669566cb-l69hx 0/1 ContainerCreating 0 41s hellok8s-go-http-6db476b8cb-dlr2z 1/1 Running 1 (7m34s ago) 22m hellok8s-go-http-6db476b8cb-glx7h 1/1 Running 1 (7m34s ago) 22m hellok8s-go-http-6db476b8cb-sfxnr 1/1 Running 1 (7m34s ago) 22m
重新部署之后我们查看 pod 可以发现,之前的 pod 仍然在正常运行,而新启动的 pod 则处于 ContainerCreating 状态。我们可以直接回退到上一个版本
1 2 3 4 5 6 7 8 9 ~ kc rollout undo deployment/hellok8s-go-http --to-revision=2 deployment.apps/hellok8s-go-http rolled back ~ kc get pods NAME READY STATUS RESTARTS AGE go-http 1/1 Running 1 (12m ago) 58m hellok8s-go-http-55669566cb-l69hx 0/1 Terminating 0 5m17s hellok8s-go-http-8b44d58c5-74mhw 1/1 Running 0 22s hellok8s-go-http-8b44d58c5-hfpjj 1/1 Running 0 20s hellok8s-go-http-8b44d58c5-lzwfm 1/1 Running 0 19s
存活探针 存活探针顾名思义就是用来检查进程的存活情况的,它支持多种方式,下面是一个例子
flat 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package mainimport ( "fmt" "io" "net/http" "time" ) func main () { started := time.Now() http.HandleFunc("/healthz" , func (w http.ResponseWriter, r *http.Request) { duration := time.Since(started) if duration.Seconds() > 15 { w.WriteHeader(500 ) w.Write([]byte (fmt.Sprintf("error: %v" , duration.Seconds()))) } else { w.WriteHeader(200 ) w.Write([]byte ("ok" )) } }) http.HandleFunc("/" , func (w http.ResponseWriter, r *http.Request) { io.WriteString(w, "[v2] Hello, Kubernetes!" ) }) http.ListenAndServe(":3000" , nil ) }
这个程序的 /healthz 接口会在启动 15 秒钟后开始持续报错,我们使用这个代码创建镜像 derobukal/hellok8s:liveness。我们先使用正常的镜像创建 depolyment,并设置存活探针配置
flat 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 apiVersion: apps/v1 kind: Deployment metadata: name: hellok8s-go-http spec: replicas: 2 selector: matchLabels: app: hellok8s template: metadata: labels: app: hellok8s spec: containers: - image: derobukal/hellok8s:v1 name: hellok8s livenessProbe: httpGet: path: /healthz port: 3000 initialDelaySeconds: 3 periodSeconds: 3
在 livenessProbe 中我们设置使用 httpGet 的方式来检查程序的存活状态,并且接口为 healthz。启动这个 deployment,一切正常
1 2 3 4 ~ kc get pods NAME READY STATUS RESTARTS AGE hellok8s-go-http-cf86fc9d6-qjt57 1/1 Running 0 8s hellok8s-go-http-cf86fc9d6-tnf9r 1/1 Running 0 8s
之后我们切换镜像为我们刚刚创建的 derobukal/hellok8s:liveness 镜像
kc set image deployment/hellok8s-go-http hellok8s=derobukal/hellok8s:liveness
然后可以看到 pod 会每隔一会儿重启一下
1 2 3 4 ~ kc get pods NAME READY STATUS RESTARTS AGE hellok8s-go-http-78fd694d74-j2kr6 1/1 Running 3 (23s ago) 2m41s hellok8s-go-http-78fd694d74-j5d5x 1/1 Running 3 (19s ago) 91s
如果我们这时候再把镜像设置为 v1,很快就可以看到 pod 恢复正常了。
就绪探针 就绪探针是用来检测程序是否已经成功启动的,例如程序是否可以接受前端的流量、是否已经可以执行相关的任务了等等。我们编写如下程序并创建 derobukal/hellok8s:readiness 镜像
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package mainimport ( "io" "net/http" ) func hello (w http.ResponseWriter, r *http.Request) { io.WriteString(w, "[v2] Hello, Kubernetes!" ) } func main () { http.HandleFunc("/healthz" , func (w http.ResponseWriter, r *http.Request) { w.WriteHeader(500 ) }) http.HandleFunc("/" , hello) http.ListenAndServe(":3000" , nil ) }
使用如下的配置创建 deployment
flat 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 apiVersion: apps/v1 kind: Deployment metadata: name: hellok8s-go-http spec: strategy: rollingUpdate: maxSurge: 1 maxUnavailable: 1 replicas: 3 selector: matchLabels: app: hellok8s template: metadata: labels: app: hellok8s spec: containers: - image: derobukal/hellok8s:v1 name: hellok8s readinessProbe: httpGet: path: /healthz port: 3000 initialDelaySeconds: 1 periodSeconds: 5 timeoutSeconds: 1 failureThreshold: 3
还是使用 /healthz 接口进行检测,启动 deployment 后发现 pod 正常启动
1 2 3 4 5 ~ kc get pods NAME READY STATUS RESTARTS AGE hellok8s-go-http-7b48477987-2x4ll 1/1 Running 0 12s hellok8s-go-http-7b48477987-hl4kt 1/1 Running 0 14s hellok8s-go-http-7b48477987-xdtvl 1/1 Running 0 14s
之后修改镜像 kc set image deployment/hellok8s-go-http hellok8s=derobukal/hellok8s:readiness
之后发现有两个 pod 一直无法进入 ready 状态
1 2 3 4 5 6 ~ kc get pods NAME READY STATUS RESTARTS AGE hellok8s-go-http-56dd6754c7-6qltj 0/1 Running 0 20s hellok8s-go-http-56dd6754c7-kmzb2 0/1 Running 0 20s hellok8s-go-http-7856db556-5d9vr 1/1 Running 0 31s hellok8s-go-http-7856db556-jctgt 1/1 Running 0 31s
任务 任务用于执行一些 job,例如如下的任务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 apiVersion: batch/v1 kind: Job metadata: name: pods-job spec: ttlSecondsAfterFinished: 10 template: spec: restartPolicy: Never containers: - command: ['sh' , '-c' , 'echo "Start Job!"; sleep 30; echo "Job Done!"' ] image: busybox name: pods-job-container
如上的任务只是简单的进行了信息的打印
1 2 3 4 5 6 7 8 9 10 11 12 13 14 ~ kc apply -f job.yaml job.batch/pods-job created ~ kc get pods NAME READY STATUS RESTARTS AGE pods-job-nthvl 0/1 ContainerCreating 0 7s ~ kc get pods NAME READY STATUS RESTARTS AGE pods-job-nthvl 1/1 Running 0 23s ~ kc get pods NAME READY STATUS RESTARTS AGE pods-job-nthvl 1/1 Running 0 48s ~ kc get pods NAME READY STATUS RESTARTS AGE pods-job-nthvl 0/1 Completed 0 56s
定时任务 定时任务 CronJob 用于执行定时任务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 apiVersion: batch/v1 kind: CronJob metadata: name: pods-cronjob spec: schedule: "*/1 * * * *" startingDeadlineSeconds: 3 concurrencyPolicy: Forbid suspend: false successfulJobsHistoryLimit: 3 failedJobsHistoryLimit: 1 jobTemplate: spec: template: spec: restartPolicy: Never containers: - command: [ 'sh' , '-c' , 'echo "Start Job!"; sleep 30; echo "Job Done!"' ] image: busybox name: pods-cronjob-container
如上这个任务会每分钟执行一次,详情如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ~ kc apply -f job.yaml cronjob.batch/pods-cronjob created ~ kc get cronjob NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE pods-cronjob */1 * * * * False 0 <none> 8s ~ kc get pods NAME READY STATUS RESTARTS AGE pods-cronjob-28410113-fs4hr 0/1 ContainerCreating 0 0s ~ kc get job NAME COMPLETIONS DURATION AGE pods-cronjob-28410113 0/1 6s 6s ~ kc logs pods-cronjob-28410113-fs4hr Start Job! Job Done! ~ kc delete cronjob pods-cronjob cronjob.batch "pods-cronjob" deleted
本文链接: https://www.nosuchfield.com/2022/10/30/Kubernetes-installation-and-use-2/