环境搭建
docker
推荐使用Docker Desktop来安装,根据操作系统选择对应的安装包即可。
https://www.docker.com/products/docker-desktop/
安装完成后通过docker run hello-world
来验证是否安装成功:
安装成功。
minikube
还需要在本地搭建一套k8s集群,这里使用[minikube][https://minikube.sigs.k8s.io/docs/start/?arch=%2Fmacos%2Farm64%2Fstable%2Fbinary+download]。
在mac中,直接用brew安装即可:
brew install minikube
如果是使用Docker Desktop的方式安装的docker,使用如下命令启动minikube即可:
minikube start --vm-driver docker --container-runtime=docker
通过minikube status
查看当前状态:
minikube常见命令如下:
•minikube stop: 不删除数据,停止VM和k8s集群•minikube delete:删除所有minikube启动后的数据•minikube ip:查看集群和docker enginer运行的ip地址•minikube pause:暂停当前资源和k8s集群•minikube status:查看当前集群状态
kubectl
安装完minikube之后,可以通过minikube kubectl
来执行相关命令,如果希望执行的命令更为简洁,可以直接安装kubectl,后续命令直接使用kubectl
即可。
mac中使用如下命令来安装:
brew install kubectl
docker hub
minikube默认镜像地址为DockerHub,因此需要在[DockerHub][https://hub.docker.com/]中注册账号,并通过`docker login`命令来登录账号。
Container
如果有如下代码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)
}
这段代码启动了HTTP服务器,监听3000端口,如果访问/
路由,就会返回[v1] Hello, Kubernetes!
如果在真实的物理环境中运行,需要安装golang环境,熟悉go module的基本使用等等,但是如果依赖于容器技术,只需要一个
Dockerfile文件,加上想要运行的代码即可。
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使用多阶段进行构建。第一阶段从golang:1.16-buster基础镜像中构建应用程序,生成可执行文件main,第二阶段基于gcr.io/distroless/base-debian10构建基础镜像,将main可执行文件复制到镜像中,开放3000端口,并将/main作为容器入口点。
注意,需要将main.go和Dockerfile放到同一目录下,下面开始docker build:
docker build . -t rynnnn617/hellok8s:v1
其中rynnnn617是在dockerhub中注册的用户名,v1表示是第一个版本。
docker images:
下面启动容器:docker run -p 3000:3000 --name hellok8s -d rynnnn617/hellok8s:v1
-p来映射端口,-d后台运行
成功。
还可以通过docker push将镜像上传到docker hub仓库中:
docker push rynnnn617/hellok8s:v1
Pod
Pod是可以在kubernetes中创建,管理和部署的最小单元。
编写如下一个yaml,来创建一个nginx的pod:
# nginx.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
spec:
containers:
- name: nginx-container
image: nginx
kind代表资源类型,metadata.name表示该pod的名字为nginx-pod(必须是唯一的),spec-containers下的字段表示容器和镜像名称。
通过kubectl apply -f nginx.yaml
命令来创建pod:
查看pod状态:
最后将端口映射出来:
kubectl port-forward nginx-pod 4000:80
也可以参考docker,通过如下命令进入pod:
kubectl exec -it nging-pod -- /bin/bsah
在shell里直接访问80端口或者映射出来后访问4000端口是一样的效果。
pod还有一些常用的命令:
kubectl logs --follow nginx-pod
kubectl exec nginx-pod -- ls
# pod "nginx-pod" deleted
kubectl delete pod nginx-pod
kubectl delete -f nginx.yaml
最后将前面通过Dockerfile和main.go构建的hellok8s:v1,用pod来实现:
apiVersion: v1
kind: Pod
metadata:
name: hellok8s
spec:
containers:
- name: hellok8s-container
image: rynnnn617/hellok8s:v1
kubectl apply -f hellok8s.yaml
kubectl get pods
kubectl port-forward hellok8s 3000:3000
pod&container
pod和container的区别如下:
•Pod 是 Kubernetes 的最小部署单位,它可以包含一个或多个容器。Pod中的容器共享网络和存储资源,它们运行在同一个命名空间下,并且可以通过本地的localhost进行通信。Pod可以共享数据,并且在同一个Pod中的容器通常用于运行协同工作的服务。•Container 是应用程序及其所有依赖的封装单位,它包含应用程序需要的所有文件、库和环境变量。在Kubernetes中,Pod中的一个或多个容器运行应用程序,并共享资源。容器是部署在Pod内的最小执行单元,通常用于封装单个应用程序或服务。
因此,可以说Pod是Kubernetes的调度单位,而容器是 Pod 中实际运行的应用程序的封装单位。Pod提供了一个逻辑上的封装,可以保证Pod内的容器共享资源,方便管理和部署应用程序。
Deployment
deployment是一种资源对象,用于对Pod进行管理控制。他提供了一种声明性的方式来定义和管理应用程序的部署,用户可依此管理应用程序的升级,扩容,回滚等操作。
扩容
首先创建一个yaml来管理hellok8s pod,deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: hellok8s-deployment
spec:
replicas: 1
selector:
matchLabels:
app: hellok8s
template:
metadata:
labels:
app: hellok8s
spec:
containers:
- image: rynnnn617/hellok8s:v1
name: hellok8s-container
kind表示为deployment类型,metadata.name同样代表deployment的名称,需要唯一,重点需要关注spec下的部分字段。
replicas表示部署的pod的数量,selector中表示deployment和pod资源关联的方式,此处代表deployment会管理所有labels为hellok8s的pod。
template部分用来定义pod资源,metadata.labels和上面的labels对应,并且deployment会自动为每个pod创建一个唯一的pod,所以不需要再定义metadata.name。
kubectl apply -f deployment.yaml
kubectl get pods
kubectl port-forward [pod-name] 3000:3000
成功,并且可以看到deployment给了pod一个随机的名称:hellok8s-deployment-5f787f87f4-dg7rg
下面尝试删除该pod:
虽然删除了一个pod,但是deployment又自动创建了一个新pod,因为在deployment.yaml中定义了pod副本数量为1.
下面尝试对其进行扩容,将replicas改为3,表示pod副本数量为3:
apply之前,通过kubectl get pods --watch
观察pod创建情况,可以看到原有的一个pod没有变化,但是pending了两个新pod,随后变为containercreating状态,最后均进入running模式,共有3个pod。仅通过修改一个参数,实现了扩容。
升级
下面模拟升级版本。
修改main.go文件,将打印输出的v1改为v2,并重新制作镜像,上传:
kubectl apply -f deployment.yaml
,再kubectl get pods
查看:
开始会报错errimagepull,随后原先的3个pod会被删除,并创建3个新的pod,验证一下:
滚动更新
在真实的生产环境中,如果需要对pod进行升级,按照前面的方式会导致在短期内,服务是完全不可用的,需要等待第一个升级完的pod正常运行才行。因此有了这里提到的滚动更新,Rolling Update.
在deployment的定义中,spec.strategy.type有两类:
•Rolling Update:逐渐增加新版本pod•Recreate:先删除旧版本pod,再增加新版本pod
Rolloing Update就能解决前面提到的问题,而对于Rolling Update,又可以通过maxSurge和maxUnavailable来控制。
•maxSurge:制定可以创建的超出期望的pod数量•maxUnavailable:制定升级过程中不可用的pod个数上限
下面先回滚之前的操作,再进行滚动升级。
kubectl rollout undo deployment hellok8s-deployment
•undo: 撤销(回滚)更新操作•deployment: 要进行回滚操作的资源类型,这里指的是 Deployment 资源类型•hellok8s-deployment: Deployment 资源的名称,即deployment.yaml中的metadata.name,并非yaml文件的文件名
回滚之后再查看一下版本:
除了前面端口映射直接访问之外,还可以通过kubectl describe pod [pod-name]
来查看pod信息,可以看到已经回滚到v1版本。
除了undo,也可以通过history命令来查看历史版本,结合-- to-revision参数来回滚到指定版本:
kubectl rollout history deployment hellok8s-deployment
kubectl rollout undo deployment/hellok8s-deployment --to-revision=2
下面修改deployment.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: rynnnn617/hellok8s:v2
name: hellok8s-container
主要的变化在于:
spec:
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
表示在升级过程中,最多可能会创建4个pod(replicas+maxSurge),最少会有两个pod存活(replicas-maxUnavailable)。
看一下效果:
可以看到,-rwqd5这个pod,是在两个pod升级完成之后再terminating,这就保证了服务的可用性。
探针
livenessProb
如果遇到死锁,导致服务不可用,就需要使用存活探测器 (livenessProb) 来监控并自动处理。
下面修改一下代码来模拟死锁的情况:
package main
import (
"fmt"
"io"
"net/http"
"time"
)
func hello(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "[v2] Hello, Kubernetes!")
}
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("/", hello)
http.ListenAndServe(":3000", nil)
}
/healthz 接口会在启动成功的 15s 内正常返回200状态码,在 15s 后,返回500。
把tag修改为liveness并推送到远程仓库。
docker build . -t rynnnn617/hellok8s:liveness
docker push rynnnn617/hellok8s:liveness
制作好image后,最后来修改deployment.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: rynnnn617/hellok8s:liveness
name: hellok8s-container
livenessProbe:
httpGet:
path: /healthz
port: 3000
initialDelaySeconds: 3
periodSeconds: 3
主要添加了最后的livenessProbe部分,代表使用http GET请求,来请求、healthz接口,端口为3000,initialDelaySeconds指定了在首次探测之前等待3秒,periodSeconds表示每3秒进行一次存活探测。
可以看到pod一直在重启,因为每个pod在15s内是正常的,超过15s,探针就会检测到其死锁状态,并进行重启,在重启后的15s内又是正常的,所以会无限重复该状态。
readiness
在 Kubernetes 中,Readiness Probe(就绪探针)是一种用来确定容器是否已经准备好接收流量的机制。通过配置 Readiness Probe,可以让 Kubernetes 在容器准备好处理请求之前等待一段时间,确保容器已经成功启动并且准备好接受流量。如果容器的 Readiness Probe 失败,Kubernetes 将认为该容器不健康,不应该接收流量,并将其从 Service 的负载均衡池中移除。
先回滚到hellok8s:v2版本:
修改main.go,访问healthz直接返回500:
package main
import (
"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.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: rynnnn617/hellok8s:bad
name: hellok8s-container
readinessProbe:
httpGet:
path: /healthz
port: 3000
initialDelaySeconds: 1
successThreshold: 5
readinessProbe:
httpGet:
path: /healthz
port: 3000
initialDelaySeconds: 1
successThreshold: 5
主要涉及的就是下面几个参数:
1.httpGet:就绪探测将使用 HTTP GET 请求来检查容器的就绪状态2.path: /healthz:指定了用于就绪探测的 HTTP GET 请求路径3.port: 3000:指定了就绪探测将连接的端口号4.initialDelaySeconds: 1:指定了容器启动后多久开始进行初次就绪检测,在此示例中,容器将会等待 1 秒钟后开始进行第一次就绪检测5.successThreshold: 5:指定了成功就绪探测的阈值。在此示例中,如果连续 5 次的就绪检测成功,Kubernetes 将认为容器已经就绪并准备好接收流量
有两个pod一直处于READY 0/1的状态,describe看一下:
readiness probe检测到500状态码,所以没法running。
Service
在k8s中,Service 是一种抽象的概念,用于定义一组具有相同逻辑功能的 Pod 的访问方式。Service 充当了 Pod 的负载衡器和稳定的访问入口,使得应用程序可以通过特定的网络端点暴露给其他服务或外部用户。
ClusterIP
首先看CLusterIP,ClusterIP 是 Kubernetes 默认的 Service 类型,这种类型的 Service 只在集群内部暴露一个 Cluster IP,其他 Pods 可以使用该 Cluster IP 来与 Service 通信。ClusterIP 类型的 Service 只能在集群内部使用,外部用户无法直接访问该 Service。
修改一下main.go,返回出当前的hostname:
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)
}
同样制作镜像,并push:
同时,更新deployment.yaml,将containers.image改为v3:
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:v3
name: hellok8s-container
下面创建一个service-hellok8s-clusterip.yaml:
apiVersion: v1
kind: Service
metadata:
name: service-hellok8s-clusterip
spec:
type: ClusterIP
selector:
app: hellok8s
ports:
- port: 3000
targetPort: 3000
看一下get service和get pod:
这里的service中,CLusterIP为10.106.174.78,进入nginx-pod来请求一下该ip:
可以看到,请求成功,并且每次返回的hostname是不同的,说明这种情况下,service接受请求,并且将其传递到后面的所有pod,自动负载均衡。
NodePort
NodePort 是 Service 的另一种类型,它可以将 Service 暴露到集群节点的一个固定端口上,并通过该端口可以从集群外部访问 Service
如图所示,该集群内有两个节点(node),都运行着hellok8s,如果创建一个NodePort类型的service,将端口进行映射,就可以通过node1-ip:port或者node2-ip:port来访问服务。
新建一个service-hellok8s-nodeport.yaml:
apiVersion: v1
kind: Service
metadata:
name: service-hellok8s-nodeport
spec:
type: NodePort
selector:
app: hellok8s
ports:
- port: 3000
nodePort: 30000
通常情况下,直接请求minikube的ip即可,但是这里报错failed to connect,因为在默认情况下,minikube会自动识别driver,本地只安装了docker desktop,所以minikube虚拟机用的就是docker,而在mac上,docker的网络设置存在一些限制,无法通过ip直连docker container。
有下面几种解决方式:
•virtualbox启动minikube•利用该项目:https://github.com/chipmk/docker-mac-net-connect•通过minikube ssh,进入minikube的container,通过127.0.0.1访问
这里采用最后一种方法:
LoadBalancer
在K8s中,LoadBalancer类型的 Service 能够将外部流量分配到 Pod 列表中,通常用于暴露应用程序,以便可以从集群外部访问。
Ingress
Ingress可以理解为service的网关,是所有流量的入口,经过配置的路由规则,将流量重定向到后端的服务。
Service主要用于内部流量管理和提供服务发现,适合简单的流量转发,而Ingress则用于更复杂的 HTTP 路由和流量管理,能够将多条外部请求路由到不同的内部服务。
其中ingress控制器是必不可少的,minikube默认使用的是nginx-ingress。
通过如下命令开启ingress-controller:
minikube addons enable ingress
删除之前所有的资源:
hellok8s.yaml:
apiVersion: v1
kind: Service
metadata:
name: service-hellok8s-clusterip
spec:
type: ClusterIP
selector:
app: hellok8s
ports:
- port: 3000
targetPort: 3000
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: hellok8s-deployment
spec:
replicas: 3
selector:
matchLabels:
app: hellok8s
template:
metadata:
labels:
app: hellok8s
spec:
containers:
- image: rynnnn617/hellok8s:v3
name: hellok8s-container
nginx.yaml:
apiVersion: v1
kind: Service
metadata:
name: service-nginx-clusterip
spec:
type: ClusterIP
selector:
app: nginx
ports:
- port: 4000
targetPort: 80
---
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
目前已经创建了三个hellok8s的pod,两个nginx的pod,service都是使用默认的CLusterIP方式。
下面编写一个ingress.yaml:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hello-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
rules:
- http:
paths:
- path: /hello
pathType: Prefix
backend:
service:
name: service-hellok8s-clusterip
port:
number: 3000
- path: /
pathType: Prefix
backend:
service:
name: service-nginx-clusterip
port:
number: 4000
metadata.name是该ingress的名称,annotations中的内容使得nginx ingress控制器不将http请求重定向到https,spec.rules定义了ingress的匹配规则,-http表示这是一个http的规则。
该 Ingress 配置定义了两个路由规则:请求路径以 /hello 开头的流量会被转发到名为 service-hellok8s-clusterip 的服务的 3000 端口,而请求/则会被转发到名为 service-nginx-clusterip的服务的 4000 端口。
跟前面nodeport一样的原因,这里需要通过minikube ssh:
从不同的路由,访问到了不同的服务。
Namespace
在K8s中,Namespace是一种用于将集群内的资源进行逻辑分组和隔离的机制。它可以帮助在同一集群中运行多个独立的工作负载,以便更好地管理和组织资源。
下面创建一个namespace.yaml:
apiVersion: v1
kind: Namespace
metadata:
name: dev
---
apiVersion: v1
kind: Namespace
metadata:
name: test
这里包含了两个namespace:dev和test。
如果要在指定的命名空间进行操作,加上-n [namespace]即可:
Configmap
ConfigMap是一种用于存储非机密的配置数据的对象,主要目的是帮助将配置信息与应用程序代码分离。他允许应用程序在运行时动态地获取配置,而无需重新构建和重新部署容器镜像。
先删除之前所有的资源:
kubectl delete deployment,service,ingress --all
下面创建v4版本的镜像,来模拟在不同环境中,数据库环境不同的场景。
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)
}
登录,打包并上传:
创建不同namespace的configmap,来存放数据库地址。
hellok8s-config-dev.yaml:
apiVersion: v1
kind: ConfigMap
metadata:
name: hellok8s-config
data:
DB_URL: "http://DB_ADDRESS_DEV"
hellok8s-config-test.yaml:
apiVersion: v1
kind: ConfigMap
metadata:
name: hellok8s-config
data:
DB_URL: "http://DB_ADDRESS_TEST"
apply:
kubectl apply -f hellok8s-config-dev.yaml -n dev
kubectl apply -f hellok8s-config-test.yaml -n test
看一下所有命名空间的configmap:
再部署一个v4的pod:
apiVersion: v1
kind: Pod
metadata:
name: hellok8s-pod
spec:
containers:
- name: hellok8s-container
image: guangzhengli/hellok8s:v4
env:
- name: DB_URL
valueFrom:
configMapKeyRef:
name: hellok8s-config
key: DB_URL
apply之后查看一下pod情况:
如果不指定-n参数,也就是不指定命名空间的话,会报错configmap not found:
这是因为前面创建的configmap是在dev和test命名空间里的,而不加参数默认是属于default。
下面分别看一下在两个命名空间内,v4的pod返回的db url:
kubectl port-forward hellok8s-pod 3000:3000 -n dev
curl http://localhost:3000
kubectl port-forward hellok8s-pod 3000:3000 -n test
curl http://localhost:3000
在不同的namespace里,返回的db_url是不同的。
Secret
在前面提到的configmap中提到,configmap可以用来存储非机密的配置数据,此时如果要存储密码等信息,或者需要对信息进行加密时,就需要secret。
一个简单的实例如下:
# hellok8s-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: hellok8s-secret
data:
DB_PASSWORD: "ZGJfcGFzc3dvcmQK"
这里DB_PASSWORD的值需要进行base64_encode,kind为Secret。
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)
}
hellok8s.yaml:
# hellok8s.yaml
apiVersion: v1
kind: Pod
metadata:
name: hellok8s-pod
spec:
containers:
- name: hellok8s-container
image: rynnnn617/hellok8s:v5
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: hellok8s-secret
key: DB_PASSWORD
和前面一样,删除所有资源,创建v5的main.go,打包镜像并上传,再创建一个pod:
转发端口,在pod的yaml中,指定了从hellok8s-secret的DB_PASSWORD中读取内容,即编码后的db_password.
Job
Job是一种控制器,用于管理一次性任务的执行。这些任务通常是批处理作业,Job 会确保这些作业成功完成,即使在运行一段时间后 Pod 失败或被重启。
直接看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"
completions指的是会创建 Pod 的数量,每个 pod 都会完成下面的任务。parallelism指的是并发执行最大数量,例如下面就会先创建 3 个 pod 并发执行任务,一旦某个 pod 执行完成,就会再创建新的 pod 来执行,直到 5 个 pod 执行完成,Job 才会被标记为完成。
restartPolicy: OnFailure表示当 Pod 的容器因为错误(非零状态码)而失败时,Kubernetes 会自动重启该 Pod。
如图,会创建5个pod,并且每个pod都会执行任务。
CronJob
相较于前面的Job,CronJob可以理解为定时任务,而非一次性任务。
与前面不同的是,需要在yaml中加上schedule:
apiVersion: batch/v1
kind: CronJob
metadata:
name: hello-cronjob
spec:
schedule: "* * * * *" # Every minute
jobTemplate:
spec:
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或者CronJob,由该任务创建的pod也会被一并删除:
Helm
Helm是 Kubernetes 的一个软件包管理工具,类似于 Linux 中的 apt 或 yum,旨在简化 Kubernetes 应用的部署和管理。Helm 通过使用Charts的概念,允许用户快速安装、升级和管理复杂的应用程序。
例如,在前面的例子中,如果需要部署资源或服务,需要一个个通过kubectl apply -f [pod][service][deployment][ingress][configmap]...
,而借助helm,可以一键完成前面的工作。
首先安装helm:
brew install helm
通过helm安装
helm repo add:直接将创建好的 hellok8s chart 添加到自己本地的仓库当中
helm install:从仓库中安装 hellok8s/hello-helm 到 k8s 集群当中。
helm repo add hellok8s https://guangzhengli.github.io/k8s-tutorials/
helm install my-hello-helm hellok8s/hello-helm --version 0.1.0
成功:
创建helm charts
首先helm create来创建一个初始的chart,目录结构如下:
打开生成的nginx-chart/Chart.yaml文件,进行如下修改:
apiVersion: v2
name: nginx-chart
description: A Helm Chart for NGINX
version: 0.1.0
appVersion: "1.21.0"
接下来,打开nginx-chart/values.yaml,并配置 NGINX 的基本信息:
replicaCount: 1
image:
repository: nginx
tag: "1.21.0"
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 80
此设置定义了 NGINX 的 Docker 镜像和 Service 的基本属性。
下面在nginx-chart/templates/目录中,修改deployment.yaml文件,以确保它从values.yaml中读取配置:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}-nginx
labels:
app: {{ .Release.Name }}-nginx
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ .Release.Name }}-nginx
template:
metadata:
labels:
app: {{ .Release.Name }}-nginx
spec:
containers:
- name: nginx
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
ports:
- containerPort: 80
确保这里的容器名和镜像信息都是从values.yaml中引用的。
同样,新增service.yaml:
apiVersion: v1
kind: Service
metadata:
name: {{ .Release.Name }}-nginx
labels:
app: {{ .Release.Name }}-nginx
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: 80
selector:
app: {{ .Release.Name }}-nginx
最后安装即可,helm名称为mynginx:
helm install my-nginx ./nginx-chart
通过如下命令检查 Release 是否已成功部署:
helm list
kubectl get deployments
kubectl get services
通过端口转发,成功访问。
如果要卸载某个Release,通过如下命令即可:
helm uninstall [helm-name]
rollback
假设已经安装了 NGINX Helm Chart,现在进行一次升级,将镜像版本改为 1.21.1
。
修改 nginx-chart/values.yaml
中Docker镜像版本:
image:
repository: nginx
tag: "1.21.1" # 修改版本
升级 Helm Release:
helm upgrade my-nginx ./nginx-chart
同样可以通过helm history命令查看所有历史版本记录。
假设要回滚到版本1,可以执行以下命令:
helm rollback my-nginx 1
多环境配置
在 Helm Chart 的多环境配置中,通常会通过不同的 values.yaml
文件来管理不同环境的设置(如开发、测试、生产等)。
在nginx-chart目录下创建不同的环境配置。
nginx-chart/values-dev.yaml:
replicaCount: 1
image:
repository: nginx
tag: "1.21.0"
service:
type: ClusterIP
port: 80
nginx-chart/values-prod.yaml:
replicaCount: 3
image:
repository: nginx
tag: "1.21.0"
service:
type: LoadBalancer
port: 80
编辑完成后,对于不同的环境,使用不同的配置文件即可。
helm install my-nginx-dev ./nginx-chart -f ./nginx-chart/values-dev.yaml
helm install my-nginx-prod ./nginx-chart -f ./nginx-chart/values-prod.yaml
同样在升级时,也可以使用 -f
参数应用不同的配置文件。
helm chart打包和发布
Helm Chart 打包是将 Chart 目录压缩为一个 .tgz
文件,以便于分发或发布。
在 nginx-chart
的父目录中,运行以下命令:
helm package nginx-chart
如图,会创建一个tgz文件。
如果想发布helm chart,就需要将 Chart 发布到一个 Helm 仓库,例如ChartMuseum的第三方仓库,或者 GitHub Pages等等。具体操作可参考官方文档。
参考链接:https://github.com/guangzhengli/k8s-tutorials
原文始发于微信公众号(Crush Sec):云原生02—K8s(全)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论