轻量应用服务器可以做网站吗,招网站建设销售,网页设计尺寸适配,如何在百度提交网站k8s相关基础知识 文章目录 k8s相关基础知识1、Container2、PodPod 与 Container 的不同Pod 其它命令 3、Deployment扩容升级版本Rolling update(滚动更新)存活探针#xff08;livenessProb#xff09;就绪探针(readiness) 4、ServiceClusterIPNodePortLoadBalancer 5、Ingres…k8s相关基础知识 文章目录 k8s相关基础知识1、Container2、PodPod 与 Container 的不同Pod 其它命令 3、Deployment扩容升级版本Rolling update(滚动更新)存活探针livenessProb就绪探针(readiness) 4、ServiceClusterIPNodePortLoadBalancer 5、Ingress6、Namespace7、ConfigMap8、Secret9、JobCronJob 10、Helm11、OthersDashboardK9s 1、Container 提示打包镜像 运行成容器 初识容器技术 压缩包与执行文件如果学过docker这一部分可以跳过
package mainimport (ionet/http
)func hello(w http.ResponseWriter, r *http.Request) {io.WriteString(w, [v1] Hello, Kubernetes!)
}func main() {http.HandleFunc(/, hello)http.ListenAndServe(:3000, nil)
}上面是一串用 Go 写的代码代码逻辑非常的简单首先启动 HTTP 服务器监听 端口当访问路由 的时候 返回字符串 。3000/[v1] Hello, Kubernetes!
在以前如果你想将这段代码运行起来并测试一下。你首先需要懂得如何下载 golang 的安装包进行安装接着需要懂得 的基本使用最后还需要了解 golang 的编译和运行命令才能将该代码运行起来。甚至在过程中可能会因为环境变量问题、操作系统问题、处理器架构等问题导致编译或运行失败。golang module
但是通过 Container (容器) 技术只需要上面的代码附带着对应的容器 文件那么你就不需要 golang 的任何知识也能将代码顺利运行起来。Dockerfile Container (容器) 是一种沙盒技术。它是基于 Linux 中 Namespace / Cgroups / chroot 等技术结合而成更多技术细节可以参看这个视频 如何自己实现一个容器。 下面就是 Go 代码对应的 简单的方案是直接使用 golang 的 alpine 镜像来打包但是因为我们后续练习需要频繁的推送镜像到 DockerHub 和拉取镜像到 k8s 集群中为了优化网络速度我们选择先在 中将上述 Go 代码编译成二进制文件再将二进制文件复制到 镜像中运行 (Dockerfile 不理解没有关系不影响后续教程学习)。Dockerfilegolang:1.16-busterbase-debian10
这样我们可以将 300MB 大小的镜像变成只有 20MB 的镜像甚至压缩上传到 DockerHub 后大小只有 10MB
# Dockerfile
FROM golang:1.16-buster AS builder
RUN mkdir /src
ADD . /src
WORKDIR /srcRUN go env -w GO111MODULEauto
RUN go build -o main .FROM gcr.io/distroless/base-debian10WORKDIR /COPY --frombuilder /src/main /main
EXPOSE 3000
ENTRYPOINT [/main]需要注意 文件需要和 文件在同一个目录下执行下方 命令第一次需要耐心等待拉取基础镜像。并且需要注意将 guangzhengli 替换成自己的 DockerHub 账号名称。 这样我们后续可以推送镜像到自己注册的 仓库当中。main.goDockerfiledocker buildDockerHub
docker build . -t guangzhengli/hellok8s:v1
# Step 1/11 : FROM golang:1.16-buster AS builder
# ...
# ...
# Step 11/11 : ENTRYPOINT [/main]
# Successfully tagged guangzhengli/hellok8s:v1docker images
# guangzhengli/hellok8s v1 f956e8cf7d18 8 days ago 25.4MBdocker build 命令完成后我们可以通过 命令查看镜像是否 build 成功最后我们执行 命令将容器启动 指定 作为端口 指定刚打包成功的镜像名称。docker imagesdocker run-p3000-d
docker run -p 3000:3000 --name hellok8s -d guangzhengli/hellok8s:v1运行成功后可以通过浏览器或者 来访问 , 查看是否成功返回字符串 .
curl http://127.0.0.1:3000 [v1] Hello, Kubernetes!这里因为我本地只用 Docker CLI而 docker runtime 是使用 所以我需要先调用 来返回 minikube IP 地址例如返回了 所以我需要访问 来判断是否成功返回字符串
最后确认没有问题使用 将镜像上传到远程的 仓库当中这样可以供他人下载使用也方便后续 下载镜像使用。 需要注意将 guangzhengli 替换成自己的 DockerHub 账号名称。docker push DockerHub Minikube
docker push guangzhengli/hellok8s:v1经过这一节的练习有没有对容器的强大有一个初步的认识呢可以想象当你想部署一个更复杂的服务时例如 NginxMySQLRedis。你只需要到 DockerHub 搜索 中搜索对应的镜像通过 下载镜像 启动服务即可而无需关系依赖和各种配置docker pulldocker run
2、Pod
提示可单独创建
如果在生产环境中运行的都是独立的单体服务那么 Container (容器) 也就够用了但是在实际的生产环境中维护着大规模的集群和各种不同的服务服务之间往往存在着各种各样的关系。而这些关系的处理才是手动管理最困难的地方。
Pod 是我们将要创建的第一个 k8s 资源也是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。在了解 pod 和 container 的区别之前我们可以先创建一个简单的 pod 试试
我们先创建 nginx.yaml 文件编写一个可以创建 nginx 的 Pod。
# nginx.yaml
# 这是一个Kubernetes Pod的YAML配置文件用于创建一个运行Nginx容器的Pod。
apiVersion: v1
kind: Pod
metadata:# 元数据信息定义Pod的名字name: nginx-pod
spec:# Pod规范部分描述了Pod中容器的具体配置containers:- # 定义一个容器name: nginx-container# 指定使用的Docker镜像image: nginx# 注释这里指定了Pod中名为nginx-container的容器将使用官方提供的Nginx镜像
其中 kind 表示我们要创建的资源是 Pod 类型 metadata.name 表示要创建的 pod 的名字这个名字需要是唯一的。 spec.containers 表示要运行的容器的名称和镜像名称。镜像默认来源 DockerHub。
我们运行第一条 k8s 命令 kubectl apply -f nginx.yaml 命令来创建 nginx Pod。
接着通过 kubectl get pods 来查看 pod 是否正常启动。
最后通过 kubectl port-forward nginx-pod 4000:80 命令将 nginx 默认的 80 端口映射到本机的 4000 端口打开浏览器或者 curl 来访问 http://127.0.0.1:4000 , 查看是否成功访问 nginx 默认页面
如果你在内部的yaml文件当中定义了port外部是无法访问的只有集群内部可以访问
kubectl apply -f nginx.yaml
# pod/nginx-pod createdkubectl get pods
# nginx-pod 1/1 Running 0 6skubectl port-forward nginx-pod 4000:80
# Forwarding from 127.0.0.1:4000 - 80
# Forwarding from [::1]:4000 - 80kubectl exec -it 可以用来进入 Pod 内容器的 Shell。通过命令下面的命令来配置 nginx 的首页内容。
kubectl exec -it nginx-pod /bin/bashecho hello kubernetes by nginx! /usr/share/nginx/html/index.htmlkubectl port-forward nginx-pod 4000:80最后可以通过浏览器或者 curl 来访问 http://127.0.0.1:4000 , 查看是否成功启动 nginx 和返回字符串 hello kubernetes by nginx!。
Pod 与 Container 的不同
回到 pod 和 container 的区别我们会发现刚刚创建出来的资源如下图所示在最内层是我们的服务 nginx运行在 container 容器当中 container (容器) 的本质是进程而 pod 是管理这一组进程的资源 所以自然 pod 可以管理多个 container在某些场景例如服务之间需要文件交换(日志收集)本地网络通信需求(使用 localhost 或者 Socket 文件进行本地通信)在这些场景中使用 pod 管理多个 container 就非常的推荐。而这也是 k8s 如何处理服务之间复杂关系的第一个例子如下图所示 Pod 其它命令
我们可以通过 logs 或者 logs -f 命令查看 pod 日志可以通过 exec -it 进入 pod 或者调用容器命令通过 delete pod 或者 delete -f nginx.yaml 的方式删除 pod 资源。这里可以看到 kubectl 所有命令。
kubectl logs --follow nginxkubectl exec nginx -- lskubectl delete pod nginx
# pod nginx deletedkubectl delete -f nginx.yaml
# pod nginx deleted最后根据我们在 container 的那节构建的 hellok8s:v1 的镜像同时参考 nginx pod 的资源定义你能独自编写出 hellok8s:v1 Pod 的资源文件吗。并通过 port-forward 到本地的 3000 端口进行访问最终得到字符串 [v1] Hello, Kubernetes!。
hellok8s:v1 Pod 资源定义和相应的命令如下所示
# hellok8s.yaml
apiVersion: v1
kind: Pod
metadata:name: hellok8s
spec:containers:- name: hellok8s-containerimage: guangzhengli/hellok8s:v13、Deployment 提示 系统内的资源创建
在生产环境中我们基本上不会直接管理 pod我们需要 kubernetes 来帮助我们来完成一些自动化操作例如自动扩容或者自动升级版本。可以想象在生产环境中我们手动部署了 10 个 hellok8s:v1 的 pod这个时候我们需要升级成 hellok8s:v2 版本我们难道需要一个一个的将 hellok8s:v1 的 pod 手动升级吗
这个时候就需要我们来看 kubeates 的另外一个资源 deployment来帮助我们管理 pod。
扩容
首先可以创建一个 deployment.yaml 的文件。来管理 hellok8s pod。
apiVersion: apps/v1
kind: Deployment
metadata:name: hellok8s-deployment
spec:replicas: 1selector:matchLabels:app: hellok8stemplate:metadata:labels:app: hellok8sspec:containers:- image: guangzhengli/hellok8s:v1name: hellok8s-container其中 kind 表示我们要创建的资源是 deployment 类型 metadata.name 表示要创建的 deployment 的名字这个名字需要是唯一的。
在 spec 里面表示首先 replicas 表示的是部署的 pod 副本数量selector 里面表示的是 deployment 资源和 pod 资源关联的方式这里表示 deployment 会管理 (selector) 所有 labelshellok8s 的 pod。
template 的内容是用来定义 pod 资源的你会发现和作业一Hellok8s Pod 资源的定义是差不多的唯一的区别是我们需要加上 metadata.labels 来和上面的 selector.matchLabels 对应起来。来表明 pod 是被 deployment 管理不用在template 里面加上 metadata.name 是因为 deployment 会主动为我们创建 pod 的唯一name。
接下来输入下面的命令可以创建 deployment 资源。通过 get 和 delete pod 命令我们会初步感受 deployment 的魅力。每次创建的 pod 名称都会变化某些命令记得替换成你的 pod 的名称
kubectl apply -f deployment.yamlkubectl get deployments
#NAME READY UP-TO-DATE AVAILABLE AGE
#hellok8s-deployment 1/1 1 1 39skubectl get pods
#NAME READY STATUS RESTARTS AGE
#hellok8s-deployment-77bffb88c5-qlxss 1/1 Running 0 119skubectl delete pod hellok8s-deployment-77bffb88c5-qlxss
#pod hellok8s-deployment-77bffb88c5-qlxss deletedkubectl get pods
#NAME READY STATUS RESTARTS AGE
#hellok8s-deployment-77bffb88c5-xp8f7 1/1 Running 0 18s我们会发现一个有趣的现象当手动删除一个 pod 资源后deployment 会自动创建一个新的 pod这和我们之前手动创建 pod 资源有本质的区别这代表着当生产环境管理着成千上万个 pod 时我们不需要关心具体的情况只需要维护好这份 deployment.yaml 文件的资源定义即可。
接下来我们通过自动扩容来加深这个知识点当我们想要将 hellok8s:v1 的资源扩容到 3 个副本时只需要将 replicas 的值设置成 3接着重新输入 kubectl apply -f deployment.yaml 即可。如下所示
apiVersion: apps/v1
kind: Deployment
metadata:name: hellok8s-deployment
spec:replicas: 3selector:matchLabels:app: hellok8stemplate:metadata:labels:app: hellok8sspec:containers:- image: guangzhengli/hellok8s:v1name: hellok8s-container可以在 kubectl apply 之前通过新建窗口执行 kubectl get pods --watch 命令来观察 pod 启动和删除的记录想要减少副本数时也很简单你可以尝试将副本数随意增大或者缩小再通过 watch 来观察它的状态。 升级版本
我们接下来尝试将所有 v1 版本的 pod 升级到 v2 版本。首先我们需要构建一份 hellok8s:v2 的版本镜像。唯一的区别就是字符串替换成了 [v2] Hello, Kubernetes!。
package mainimport (ionet/http
)func hello(w http.ResponseWriter, r *http.Request) {io.WriteString(w, [v2] Hello, Kubernetes!)
}func main() {http.HandleFunc(/, hello)http.ListenAndServe(:3000, nil)
}将 hellok8s:v2 推到 DockerHub 仓库中。
docker build . -t guangzhengli/hellok8s:v2
docker push guangzhengli/hellok8s:v2apiVersion: apps/v1
kind: Deployment
metadata:name: hellok8s-deployment
spec:replicas: 3selector:matchLabels:app: hellok8stemplate:metadata:labels:app: hellok8sspec:containers:- image: guangzhengli/hellok8s:v2name: hellok8s-container接着编写 v2 版本的 deployment 资源文件。
kubectl apply -f deployment.yaml
# deployment.apps/hellok8s-deployment configuredkubectl get pods
# NAME READY STATUS RESTARTS AGE
# hellok8s-deployment-66799848c4-kpc6q 1/1 Running 0 3s
# hellok8s-deployment-66799848c4-pllj6 1/1 Running 0 3s
# hellok8s-deployment-66799848c4-r7qtg 1/1 Running 0 3skubectl port-forward hellok8s-deployment-66799848c4-kpc6q 3000:3000
# Forwarding from 127.0.0.1:3000 - 3000
# Forwarding from [::1]:3000 - 3000# open another terminal
curl http://localhost:3000
# [v2] Hello, Kubernetes!你也可以输入 kubectl describe pod hellok8s-deployment-66799848c4-kpc6q 来看是否是 v2 版本的镜像。简而言之就是不换版本的情况下换了v2的镜像得到了更新
Rolling update(滚动更新)
如果我们在生产环境上管理着多个副本的 hellok8s:v1 版本的 pod我们需要更新到 v2 的版本像上面那样的部署方式是可以的但是也会带来一个问题就是所有的副本在同一时间更新这会导致我们 hellok8s 服务在短时间内是不可用的因为所有 pod 都在升级到 v2 版本的过程中需要等待某个 pod 升级完成后才能提供服务。
这个时候我们就需要滚动更新 (rolling update)在保证新版本 v2 的 pod 还没有 ready 之前先不删除 v1 版本的 pod。
在 deployment 的资源定义中, spec.strategy.type 有两种选择:
RollingUpdate: 逐渐增加新版本的 pod逐渐减少旧版本的 pod。Recreate: 在新版本的 pod 增加前先将所有旧版本 pod 删除。
大多数情况下我们会采用滚动更新 (RollingUpdate) 的方式滚动更新又可以通过 maxSurge 和 maxUnavailable 字段来控制升级 pod 的速率具体可以详细看官网定义。
maxSurge: 最大峰值用来指定可以创建的超出期望 Pod 个数的 Pod 数量。maxUnavailable: 最大不可用用来指定更新过程中不可用的 Pod 的个数上限。
我们先输入命令回滚我们的 deployment输入 kubectl describe pod 会发现 deployment 已经把 v2 版本的 pod 回滚到 v1 的版本。
kubectl rollout undo deployment hellok8s-deploymentkubectl get pods
# NAME READY STATUS RESTARTS AGE
# hellok8s-deployment-77bffb88c5-cvm5c 1/1 Running 0 39s
# hellok8s-deployment-77bffb88c5-lktbl 1/1 Running 0 41s
# hellok8s-deployment-77bffb88c5-nh82z 1/1 Running 0 37skubectl describe pod hellok8s-deployment-77bffb88c5-cvm5c
# Image: guangzhengli/hellok8s:v1除了上面的命令还可以用 history 来查看历史版本--to-revision2 来回滚到指定版本。
kubectl rollout history deployment hellok8s-deployment
kubectl rollout undo deployment/hellok8s-deployment --to-revision2接着设置 strategyrollingUpdate , maxSurge1 , maxUnavailable1 和 replicas3 到 deployment.yaml 文件中。这个参数配置意味着最大可能会创建 4 个 hellok8s pod (replicas maxSurge)最小会有 2 个 hellok8s pod 存活 (replicas - maxUnavailable)。
apiVersion: apps/v1
kind: Deployment
metadata:name: hellok8s-deployment
spec:strategy:rollingUpdate:maxSurge: 1maxUnavailable: 1replicas: 3selector:matchLabels:app: hellok8stemplate:metadata:labels:app: hellok8sspec:containers:- image: guangzhengli/hellok8s:v2name: hellok8s-container存活探针livenessProb 存活探测器来确定什么时候要重启容器。 例如存活探测器可以探测到应用死锁应用程序在运行但是无法继续执行后面的步骤情况。 重启这种状态下的容器有助于提高应用的可用性即使其中存在缺陷。-- LivenessProb 在生产中有时候因为某些 bug 导致应用死锁或者线程耗尽了最终会导致应用无法继续提供服务这个时候如果没有手段来自动监控和处理这一问题的话可能会导致很长一段时间无人发现。kubelet 使用存活探测器 (livenessProb) 来确定什么时候要重启容器。
接下来我们写一个 /healthz 接口来说明 livenessProb 如何使用。 /healthz 接口会在启动成功的 15s 内正常返回 200 状态码在 15s 后会一直返回 500 的状态码。
package mainimport (fmtionet/httptime
)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)
}# Dockerfile
FROM golang:1.16-buster AS builder
RUN mkdir /src
ADD . /src
WORKDIR /srcRUN go env -w GO111MODULEauto
RUN go build -o main .FROM gcr.io/distroless/base-debian10WORKDIR /COPY --frombuilder /src/main /main
EXPOSE 3000
ENTRYPOINT [/main]Dockerfile 的编写和原来保持一致我们把 tag 修改为 liveness 并推送到远程仓库。
docker build . -t guangzhengli/hellok8s:liveness
docker push guangzhengli/hellok8s:liveness最后编写 deployment 的定义这里使用存活探测方式是使用 HTTP GET 请求请求的是刚才定义的 /healthz 接口periodSeconds 字段指定了 kubelet 每隔 3 秒执行一次存活探测。 initialDelaySeconds 字段告诉 kubelet 在执行第一次探测前应该等待 3 秒。如果服务器上 /healthz 路径下的处理程序返回成功代码则 kubelet 认为容器是健康存活的。 如果处理程序返回失败代码则 kubelet 会杀死这个容器并将其重启。
apiVersion: apps/v1
kind: Deployment
metadata:name: hellok8s-deployment
spec:strategy:rollingUpdate:maxSurge: 1maxUnavailable: 1replicas: 3selector:matchLabels:app: hellok8stemplate:metadata:labels:app: hellok8sspec:containers:- image: guangzhengli/hellok8s:livenessname: hellok8s-containerlivenessProbe:httpGet:path: /healthzport: 3000initialDelaySeconds: 3periodSeconds: 3通过 get 或者 describe 命令可以发现 pod 一直处于重启当中。
kubectl apply -f deployment.yamlkubectl get pods
# NAME READY STATUS RESTARTS AGE
# hellok8s-deployment-5995ff9447-d5fbz 1/1 Running 4 (6s ago) 102s
# hellok8s-deployment-5995ff9447-gz2cx 1/1 Running 4 (5s ago) 101s
# hellok8s-deployment-5995ff9447-rh29x 1/1 Running 4 (6s ago) 102skubectl describe pod hellok8s-68f47f657c-zwn6g# ...
# ...
# ...
# Events:
# Type Reason Age From Message
# ---- ------ ---- ---- -------
# Normal Scheduled 12m default-scheduler Successfully assigned default/hellok8s-deployment-5995ff9447-rh29x to minikube
# Normal Pulled 11m (x4 over 12m) kubelet Container image guangzhengli/hellok8s:liveness already present on machine
# Normal Created 11m (x4 over 12m) kubelet Created container hellok8s-container
# Normal Started 11m (x4 over 12m) kubelet Started container hellok8s-container
# Normal Killing 11m (x3 over 12m) kubelet Container hellok8s-container failed liveness probe, will be restarted
# Warning Unhealthy 11m (x10 over 12m) kubelet Liveness probe failed: HTTP probe failed with statuscode: 500
# Warning BackOff 2m41s (x36 over 10m) kubelet Back-off restarting failed container就绪探针(readiness) 就绪探测器可以知道容器何时准备好接受请求流量当一个 Pod 内的所有容器都就绪时才能认为该 Pod 就绪。 这种信号的一个用途就是控制哪个 Pod 作为 Service 的后端。 若 Pod 尚未就绪会被从 Service 的负载均衡器中剔除。-- ReadinessProb 在生产环境中升级服务的版本是日常的需求这时我们需要考虑一种场景即当发布的版本存在问题就不应该让它升级成功。kubelet 使用就绪探测器可以知道容器何时准备好接受请求流量当一个 pod 升级后不能就绪即不应该让流量进入该 pod在配合 rollingUpate 的功能下也不能允许升级版本继续下去否则服务会出现全部升级完成导致所有服务均不可用的情况。 kubectl rollout undo deployment hellok8s-deployment --to-revision2这里我们把服务回滚到 hellok8s:v2 的版本可以通过上面学习的方法进行回滚。
package mainimport (ionet/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)
}在 build 阶段我们将 tag 设置为 bad打包后 push 到远程仓库
docker build . -t guangzhengli/hellok8s:baddocker push guangzhengli/hellok8s:bad接着编写 deployment 资源文件Probe 有很多配置字段可以使用这些字段精确地控制就绪检测的行为
initialDelaySeconds容器启动后要等待多少秒后才启动存活和就绪探测器 默认是 0 秒最小值是 0。periodSeconds执行探测的时间间隔单位是秒。默认是 10 秒。最小值是 1。timeoutSeconds探测的超时后等待多少秒。默认值是 1 秒。最小值是 1。successThreshold探测器在失败后被视为成功的最小连续成功数。默认值是 1。 存活和启动探测的这个值必须是 1。最小值是 1。failureThreshold当探测失败时Kubernetes 的重试次数。 对存活探测而言放弃就意味着重新启动容器。 对就绪探测而言放弃意味着 Pod 会被打上未就绪的标签。默认值是 3。最小值是 1。
apiVersion: apps/v1
kind: Deployment
metadata:name: hellok8s-deployment
spec:strategy:rollingUpdate:maxSurge: 1maxUnavailable: 1replicas: 3selector:matchLabels:app: hellok8stemplate:metadata:labels:app: hellok8sspec:containers:- image: guangzhengli/hellok8s:badname: hellok8s-containerreadinessProbe:httpGet:path: /healthzport: 3000initialDelaySeconds: 1successThreshold: 5通过 get 命令可以发现两个 pod 一直处于还没有 Ready 的状态当中通过 describe 命令可以看到是因为 Readiness probe failed: HTTP probe failed with statuscode: 500 的原因。又因为设置了最小不可用的服务数量为maxUnavailable1这样能保证剩下两个 v2 版本的 hellok8s 能继续提供服务
kubectl apply -f deployment.yamlkubectl get pods
# NAME READY STATUS RESTARTS AGE
# hellok8s-deployment-66799848c4-8xzsz 1/1 Running 0 102s
# hellok8s-deployment-66799848c4-m9dl5 1/1 Running 0 102s
# hellok8s-deployment-9c57c7f56-rww7k 0/1 Running 0 26s
# hellok8s-deployment-9c57c7f56-xt9tw 0/1 Running 0 26skubectl describe pod hellok8s-deployment-9c57c7f56-rww7k
# Events:
# Type Reason Age From Message
# ---- ------ ---- ---- -------
# Normal Scheduled 74s default-scheduler Successfully assigned default/hellok8s-deployment-9c57c7f56-rww7k to minikube
# Normal Pulled 73s kubelet Container image guangzhengli/hellok8s:bad already present on machine
# Normal Created 73s kubelet Created container hellok8s-container
# Normal Started 73s kubelet Started container hellok8s-container
# Warning Unhealthy 0s (x10 over 72s) kubelet Readiness probe failed: HTTP probe failed with statuscode: 5004、Service ClusterIP 对pod做管理 把对应的ip 保存在Endpoints NodePort 对node 进行管理与内部容器进行映射 LoadBalancer对外部访问做负载均衡机制到node 再通过NodePort 映射到内部pod到容器 经过前面几节的练习可能你会有一些疑惑
为什么 pod 不就绪 (Ready) 的话kubernetes 不会将流量重定向到该 pod这是怎么做到的 前面访问服务的方式是通过 port-forword 将 pod 的端口暴露到本地不仅需要写对 pod 的名字一旦 deployment 重新创建新的 podpod 名字和 IP 地址也会随之变化如何保证稳定的访问地址呢。 如果使用 deployment 部署了多个 Pod 副本如何做负载均衡呢 kubernetes 提供了一种名叫 Service 的资源帮助解决这些问题它为 pod 提供一个稳定的 Endpoint。Service 位于 pod 的前面负责接收请求并将它们传递给它后面的所有pod。一旦服务中的 Pod 集合发生更改Endpoints 就会被更新请求的重定向自然也会导向最新的 pod。
ClusterIP
我们先来看看 Service 默认使用的 ClusterIP 类型首先做一些准备工作在之前的 hellok8s:v2 版本上加上返回当前服务所在的 hostname 功能升级到 v3 版本。
package mainimport (fmtionet/httpos
)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)
}Dockerfile 和之前保持一致打包 tagv3 并推送到远程仓库。
docker build . -t guangzhengli/hellok8s:v3docker push guangzhengli/hellok8s:v3修改 deployment 的 hellok8s 为 v3 版本。执行 kubectl apply -f deployment.yaml 更新 deployment。
apiVersion: apps/v1
kind: Deployment
metadata:name: hellok8s-deployment
spec:replicas: 3selector:matchLabels:app: hellok8stemplate:metadata:labels:app: hellok8sspec:containers:- image: guangzhengli/hellok8s:v3name: hellok8s-container接下来是 Service 资源的定义我们使用 ClusterIP 的方式定义 Service通过 kubernetes 集群的内部 IP 暴露服务当我们只需要让集群中运行的其他应用程序访问我们的 pod 时就可以使用这种类型的Service。首先创建一个 service-hellok8s-clusterip.yaml 文件。
apiVersion: v1
kind: Service
metadata:name: service-hellok8s-clusterip
spec:type: ClusterIPselector:app: hellok8sports:- port: 3000targetPort: 3000首先通过 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 会不会发生变化。
kubectl apply -f service-hellok8s-clusterip.yamlkubectl get endpoints
# NAME ENDPOINTS AGE
# service-hellok8s-clusterip 172.17.0.10:3000,172.17.0.2:3000,172.17.0.3:3000 10skubectl get pod -o wide
# NAME READY STATUS RESTARTS AGE IP NODE
# hellok8s-deployment-5d5545b69c-24lw5 1/1 Running 0 112s 172.17.0.7 minikube
# hellok8s-deployment-5d5545b69c-9g94t 1/1 Running 0 112s 172.17.0.3 minikube
# hellok8s-deployment-5d5545b69c-9gm8r 1/1 Running 0 112s 172.17.0.2 minikube
# nginx 1/1 Running 0 112s 172.17.0.9 minikubekubectl get service
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# service-hellok8s-clusterip ClusterIP 10.104.96.153 none 3000/TCP 10s接着我们可以通过在集群其它应用中访问 service-hellok8s-clusterip 的 IP 地址 10.104.96.153 来访问 hellok8s:v3 服务。
这里通过在集群内创建一个 nginx 来访问 hellok8s 服务。创建后进入 nginx 容器来用 curl 命令访问 service-hellok8s-clusterip 。
apiVersion: v1
kind: Pod
metadata:name: nginxlabels:app: nginx
spec:containers:- name: nginx-containerimage: nginxkubectl get pods
# NAME READY STATUS RESTARTS AGE
# hellok8s-deployment-5d5545b69c-24lw5 1/1 Running 0 27m
# hellok8s-deployment-5d5545b69c-9g94t 1/1 Running 0 27m
# hellok8s-deployment-5d5545b69c-9gm8r 1/1 Running 0 27m
# nginx 1/1 Running 0 41mkubectl get service
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# service-hellok8s-clusterip ClusterIP 10.104.96.153 none 3000/TCP 10skubectl exec -it nginx-pod /bin/bash
# rootnginx-pod:/# curl 10.104.96.153:3000
# [v3] Hello, Kubernetes!, From host: hellok8s-deployment-5d5545b69c-9gm8r
# rootnginx-pod:/# curl 10.104.96.153:3000
#[v3] Hello, Kubernetes!, From host: hellok8s-deployment-5d5545b69c-9g94t可以看到我们多次 curl 10.104.96.153:3000 访问 hellok8s Service IP 地址返回的 hellok8s:v3 hostname 不一样说明 Service 可以接收请求并将它们传递给它后面的所有 pod还可以自动负载均衡。你也可以试试增加或者减少 hellok8s:v3 pod 副本数量观察 Service 的请求是否会动态变更。调用过程如下图所示 除了上述的 ClusterIp 的方式外Kubernetes ServiceTypes 允许指定你所需要的 Service 类型默认是 ClusterIP。Type 的值包括如下
ClusterIP通过集群的内部 IP 暴露服务选择该值时服务只能够在集群内部访问。 这也是默认的 ServiceType。NodePort通过每个节点上的 IP 和静态端口NodePort暴露服务。 NodePort 服务会路由到自动创建的 ClusterIP 服务。 通过请求 节点 IP:节点端口你可以从集群的外部访问一个 NodePort 服务。LoadBalancer使用云提供商的负载均衡器向外部暴露服务。 外部负载均衡器可以将流量路由到自动创建的 NodePort 服务和 ClusterIP 服务上。ExternalName通过返回 CNAME 和对应值可以将服务映射到 externalName 字段的内容例如foo.bar.example.com。 无需创建任何类型代理。
NodePort NodePort 对node 进行管理与内部容器进行映射 我们知道kubernetes 集群并不是单机运行它管理着多台节点即 Node可以通过每个节点上的 IP 和静态端口NodePort暴露服务。如下图所示如果集群内有两台 Node 运行着 hellok8s:v3我们创建一个 NodePort 类型的 Service将 hellok8s:v3 的 3000 端口映射到 Node 机器的 30000 端口 (在 30000-32767 范围内)就可以通过访问 http://node1-ip:30000 或者 http://node2-ip:30000 访问到服务。 这里以 minikube 为例我们可以通过 minikube ip 命令拿到 k8s cluster node IP地址。下面的教程都以我本机的 192.168.59.100 为例需要替换成你的 IP 地址。
minikube ip
# 192.168.59.100接着以 NodePort 的 ServiceType 创建一个 Service 来接管 pod 流量。通过minikube 节点上的 IP 192.168.59.100 暴露服务。 NodePort 服务会路由到自动创建的 ClusterIP 服务。 通过请求 节点 IP:节点端口 – 192.168.59.100:30000你可以从集群的外部访问一个 NodePort 服务最终重定向到 hellok8s:v3 的 3000 端口。
apiVersion: v1
kind: Service
metadata:name: service-hellok8s-nodeport
spec:type: NodePortselector:app: hellok8sports:- port: 3000nodePort: 30000创建 service-hellok8s-nodeport Service 后使用 curl 命令或者浏览器访问 http://192.168.59.100:30000 可以得到结果。
kubectl apply -f service-hellok8s-nodeport.yamlkubectl get service
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# service-hellok8s-nodeport NodePort 10.109.188.161 none 3000:30000/TCP 28skubectl get pods
# NAME READY STATUS RESTARTS AGE
# hellok8s-deployment-5d5545b69c-24lw5 1/1 Running 0 27m
# hellok8s-deployment-5d5545b69c-9g94t 1/1 Running 0 27m
# hellok8s-deployment-5d5545b69c-9gm8r 1/1 Running 0 27mcurl http://192.168.59.100:30000
# [v3] Hello, Kubernetes!, From host: hellok8s-deployment-5d5545b69c-9g94tcurl http://192.168.59.100:30000
# [v3] Hello, Kubernetes!, From host: hellok8s-deployment-5d5545b69c-24lw5如果本地使用 Docker Desktopminikube start --driverdocker的话那你大概率无法通过minikube ip获取到的ip地址来请求,因为 docker 部分网络限制导致无法通过 ip 直连 docker container这代表 NodePort 类型的 Service、Ingress 组件都无法通过 minikube ip 提供的 ip 地址来访问。无法直接访问Node IP。你可以通过minikube service service-hellok8s-nodeport --url来公开服务然后通过curl或者浏览器访问。
minikube service service-hellok8s-nodeport --url
# http://127.0.0.1:50896
# Because you are using a Docker driver on windows, the terminal needs to be open to run it.
curl http://127.0.0.1:50896
# [v3] Hello, Kubernetes!, From host: hellok8s-deployment-559cfdd58c-zp2pc
curl http://127.0.0.1:50896
# [v3] Hello, Kubernetes!, From host: hellok8s-deployment-559cfdd58c-2j2x2LoadBalancer LoadBalancer对外部访问做负载均衡机制到node 再通过NodePort 映射到内部pod到容器 LoadBalancer 是使用云提供商的负载均衡器向外部暴露服务。 外部负载均衡器可以将流量路由到自动创建的 NodePort 服务和 ClusterIP 服务上假如你在 AWS 的 EKS 集群上创建一个 Type 为 LoadBalancer 的 Service。它会自动创建一个 ELB (Elastic Load Balancer) 并可以根据配置的 IP 池中自动分配一个独立的 IP 地址可以供外部访问。
这里因为我们使用的是 minikube可以使用 minikube tunnel 来辅助创建 LoadBalancer 的 EXTERNAL_IP具体教程可以查看官网文档但是和实际云提供商的 LoadBalancer 还是有本质区别所以 Repository 不做更多阐述有条件的可以使用 AWS 的 EKS 集群上创建一个 ELB (Elastic Load Balancer) 试试。
下图显示 LoadBalancer 的 Service 架构图。
5、Ingress 提示按照nginx的配置文件去理解 Ingress 公开从集群外部到集群内服务的 HTTP 和 HTTPS 路由。 流量路由由 Ingress 资源上定义的规则控制。Ingress 可为 Service 提供外部可访问的 URL、负载均衡流量、 SSL/TLS以及基于名称的虚拟托管。你必须拥有一个 Ingress 控制器 才能满足 Ingress 的要求。 仅创建 Ingress 资源本身没有任何效果。 Ingress 控制器 通常负责通过负载均衡器来实现 Ingress例如 minikube 默认使用的是 nginx-ingress目前 minikube 也支持 Kong-Ingress。
Ingress 可以“简单理解”为服务的网关 Gateway它是所有流量的入口经过配置的路由规则将流量重定向到后端的服务。
在 minikube 中可以通过下面命令开启 Ingress-Controller 的功能。默认使用的是 nginx-ingress。。
minikube addons enable ingress接着删除之前创建的所有 pod, deployment, service 资源。
kubectl delete deployment,service --all接着根据之前的教程创建 hellok8s:v3 和 nginx 的deployment与 service 资源。Service 的 type 为 ClusterIP 即可。
hellok8s:v3 的端口映射为 3000:3000nginx 的端口映射为 4000:80这里后续写 Ingress Route 规则时会用到。
apiVersion: v1
kind: Service
metadata:name: service-hellok8s-clusterip
spec:type: ClusterIPselector:app: hellok8sports:- port: 3000targetPort: 3000---apiVersion: apps/v1
kind: Deployment
metadata:name: hellok8s-deployment
spec:replicas: 3selector:matchLabels:app: hellok8stemplate:metadata:labels:app: hellok8sspec:containers:- image: guangzhengli/hellok8s:v3name: hellok8s-containerapiVersion: v1
kind: Service
metadata:name: service-nginx-clusterip
spec:type: ClusterIPselector:app: nginxports:- port: 4000targetPort: 80---apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-deployment
spec:replicas: 2selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- image: nginxname: nginx-containerkubectl apply -f hellok8s.yaml
# service/service-hellok8s-clusterip created
# deployment.apps/hellok8s-deployment createdkubectl apply -f nginx.yaml
# service/service-nginx-clusterip created
# deployment.apps/nginx-deployment createdkubectl get pods
# NAME READY STATUS RESTARTS AGE
# hellok8s-deployment-5d5545b69c-4wvmf 1/1 Running 0 55s
# hellok8s-deployment-5d5545b69c-qcszp 1/1 Running 0 55s
# hellok8s-deployment-5d5545b69c-sn7mn 1/1 Running 0 55s
# nginx-deployment-d47fd7f66-d9r7x 1/1 Running 0 34s
# nginx-deployment-d47fd7f66-hp5nf 1/1 Running 0 34skubectl get service
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# service-hellok8s-clusterip ClusterIP 10.97.88.18 none 3000/TCP 77s
# service-nginx-clusterip ClusterIP 10.103.161.247 none 4000/TCP 56s这样在 k8s 集群中就有 3 个 hellok8s:v3 的 pod2 个 nginx 的 pod。并且hellok8s:v3 的端口映射为 3000:3000nginx 的端口映射为 4000:80。在这个基础上接下来编写 Ingress 资源的定义nginx.ingress.kubernetes.io/ssl-redirect: false 的意思是这里关闭 https 连接只使用 http 连接。
匹配前缀为 /hello 的路由规则重定向到 hellok8s:v3 服务匹配前缀为 / 的跟路径重定向到 nginx。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:name: hello-ingressannotations:# We are defining this annotation to prevent nginx# from redirecting requests to https for nownginx.ingress.kubernetes.io/ssl-redirect: false
spec:rules:- http:paths:- path: /hellopathType: Prefixbackend:service:name: service-hellok8s-clusteripport:number: 3000- path: /pathType: Prefixbackend:service:name: service-nginx-clusteripport:number: 4000kubectl apply -f ingress.yaml
# ingress.extensions/hello-ingress createdkubectl get ingress
# NAME CLASS HOSTS ADDRESS PORTS AGE
# hello-ingress nginx * 80 16s# replace 192.168.59.100 by your minikube ip
curl http://192.168.59.100/hello
# [v3] Hello, Kubernetes!, From host: hellok8s-deployment-5d5545b69c-sn7mncurl http://192.168.59.100/
# (....Thank you for using nginx.....)这里和service一样如果本地使用 Docker Desktopminikube start --driverdocker的话那你大概率无法通过minikube ip获取到的ip地址来请求你可以先通过minikube service list来查看服务列表然后通过minikube service ingress-nginx-controller -n ingress-nginx --url来公开服务然后通过curl或者浏览器来访问。
minikube service list
# |---------------|------------------------------------|--------------|---------------------------|
# | NAMESPACE | NAME | TARGET PORT | URL |
# |---------------|------------------------------------|--------------|---------------------------|
# | default | kubernetes | No node port |
# | default | service-hellok8s-clusterip | No node port |
# | default | service-nginx-clusterip | No node port |
# | ingress-nginx | ingress-nginx-controller | http/80 | http://192.168.49.2:32339 |
# | | | https/443 | http://192.168.49.2:32223 |
# | ingress-nginx | ingress-nginx-controller-admission | No node port |
# | kube-system | kube-dns | No node port |
# |---------------|------------------------------------|--------------|---------------------------|
minikube service ingress-nginx-controller -n ingress-nginx --url
# http://127.0.0.1:61691 http
# http://127.0.0.1:61692 https
# ❗ Because you are using a Docker driver on windows, the terminal needs to be open to run it.
# 第一个是http第二个是https这里我们只需要http所以我们只需要第一个地址
curl http://127.0.0.1:61691/hello
# [v3] Hello, Kubernetes!, From host: hellok8s-deployment-5d5545b69c-sn7mn
curl http://127.0.0.1:61691/
# (....Thank you for using nginx.....)上面的教程中将所有流量都发送到 Ingress 中如下图所示
6、Namespace
提示类似于dev test pre pro 环境隔离 在实际的开发当中有时候我们需要不同的环境来做开发和测试例如 dev 环境给开发使用test 环境给 QA 使用那么 k8s 能不能在不同环境 dev test uat prod 中区分资源让不同环境的资源独立互相不影响呢答案是肯定的k8s 提供了名为 Namespace 的资源来帮助隔离资源。
在 Kubernetes 中名字空间Namespace 提供一种机制将同一集群中的资源划分为相互隔离的组。 同一名字空间内的资源名称要唯一但跨名字空间时没有这个要求。 名字空间作用域仅针对带有名字空间的对象例如 Deployment、Service 等。
前面的教程中默认使用的 namespace 是 default。
下面展示如何创建一个新的 namespace namespace.yaml 文件定义了两个不同的 namespace分别是 dev 和 test。
apiVersion: v1
kind: Namespace
metadata:name: dev---apiVersion: v1
kind: Namespace
metadata:name: test可以通过kubectl apply -f namespaces.yaml 创建两个新的 namespace分别是 dev 和 test
kubectl apply -f namespaces.yaml
# namespace/dev created
# namespace/test createdkubectl get namespaces
# NAME STATUS AGE
# default Active 215d
# dev Active 2m44s
# ingress-nginx Active 110d
# kube-node-lease Active 215d
# kube-public Active 215d
# kube-system Active 215d
# test Active 2m44s那么如何在新的 namespace 下创建资源和获取资源呢只需要在命令后面加上 -n namespace 即可。例如根据上面教程中在名为 dev 的 namespace 下创建 hellok8s:v3 的 deployment 资源。
kubectl apply -f deployment.yaml -n devkubectl get pods -n dev7、ConfigMap
上面的教程提到我们在不同环境 dev test uat prod 中区分资源可以让其资源独立互相不受影响但是随之而来也会带来一些问题例如不同环境的数据库的地址往往是不一样的那么如果在代码中写同一个数据库的地址就会出现问题。
K8S 使用 ConfigMap 来将你的配置数据和应用程序代码分开将非机密性的数据保存到键值对中。ConfigMap 在设计上不是用来保存大量数据的。在 ConfigMap 中保存的数据不可超过 1 MiB。如果你需要保存超出此尺寸限制的数据你可能考虑挂载存储卷。
下面我们可以来看一个例子我们修改之前代码假设不同环境的数据库地址不同下面代码从环境变量中获取 DB_URL并将它返回。
package mainimport (fmtionet/httpos
)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)
}构建 hellok8s:v4 的镜像推送到远程仓库。并删除之前创建的所有资源。
docker build . -t guangzhengli/hellok8s:v4
docker push guangzhengli/hellok8s:v4kubectl delete deployment,service,ingress --all接下来创建不同 namespace 的 configmap 来存放 DB_URL。 创建 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分别在 dev test 两个 namespace 下创建相同的 ConfigMap名字都叫 hellok8s-config但是存放的 Pair 对中 Value 值不一样。
kubectl apply -f hellok8s-config-dev.yaml -n dev
# configmap/hellok8s-config createdkubectl apply -f hellok8s-config-test.yaml -n test
# configmap/hellok8s-config createdkubectl get configmap --all-namespaces
NAMESPACE NAME DATA AGE
dev hellok8s-config 1 3m12s
test hellok8s-config 1 2m1s接着使用 POD 的方式来部署 hellok8s:v4其中 env.name 表示的是将 configmap 中的值写进环境变量这样代码从环境变量中获取 DB_URL这个 KEY 名称必须保持一致。valueFrom 代表从哪里读取configMapKeyRef 这里表示从名为 hellok8s-config 的 configMap 中读取 KEYDB_URL 的 Value
apiVersion: v1
kind: Pod
metadata:name: hellok8s-pod
spec:containers:- name: hellok8s-containerimage: guangzhengli/hellok8s:v4env:- name: DB_URLvalueFrom:configMapKeyRef:name: hellok8s-configkey: DB_URL下面分别在 dev test 两个 namespace 下创建 hellok8s:v4接着通过 port-forward 的方式访问不同 namespace 的服务可以看到返回的 Get Database Connect URL: http://DB_ADDRESS_TEST 是不一样的
kubectl apply -f hellok8s.yaml -n dev
# pod/hellok8s-pod createdkubectl apply -f hellok8s.yaml -n test
# pod/hellok8s-pod createdkubectl port-forward hellok8s-pod 3000:3000 -n devcurl http://localhost:3000
# [v4] Hello, Kubernetes! From host: hellok8s-pod, Get Database Connect URL: http://DB_ADDRESS_DEVkubectl port-forward hellok8s-pod 3000:3000 -n testcurl http://localhost:3000
# [v4] Hello, Kubernetes! From host: hellok8s-pod, Get Database Connect URL: http://DB_ADDRESS_TEST8、Secret
上面提到我们会选择以 configmap 的方式挂载配置信息但是当我们的配置信息需要加密的时候 configmap 就无法满足这个要求。例如上面要挂载数据库密码的时候就需要明文挂载。
这个时候就需要 Secret 来存储加密信息虽然在资源文件的编码上只是通过 Base64 的方式简单编码但是在实际生产过程中可以通过 pipeline 或者专业的 AWS KMS 服务进行密钥管理。这样就大大减少了安全事故。 Secret 是一种包含少量敏感信息例如密码、令牌或密钥的对象。由于创建 Secret 可以独立于使用它们的 Pod 因此在创建、查看和编辑 Pod 的工作流程中暴露 Secret及其数据的风险较小。 Kubernetes 和在集群中运行的应用程序也可以对 Secret 采取额外的预防措施 例如避免将机密数据写入非易失性存储。 默认情况下Kubernetes Secret 未加密地存储在 API 服务器的底层数据存储etcd中。 任何拥有 API 访问权限的人都可以检索或修改 Secret任何有权访问 etcd 的人也可以。 此外任何有权限在命名空间中创建 Pod 的人都可以使用该访问权限读取该命名空间中的任何 Secret 这包括间接访问例如创建 Deployment 的能力。 为了安全地使用 Secret请至少执行以下步骤 为 Secret 启用静态加密启用或配置 RBAC 规则来限制读取和写入 Secret 的数据包括通过间接方式。需要注意的是被准许创建 Pod 的人也隐式地被授权获取 Secret 内容。在适当的情况下还可以使用 RBAC 等机制来限制允许哪些主体创建新 Secret 或替换现有 Secret。 Secret 的资源定义和 ConfigMap 结构基本一致唯一区别在于 kind 是 Secret还有 Value 需要 Base64 编码你可以通过下面命令快速 Base64 编解码。当然 Secret 也提供了一种 stringData可以不需要 Base64 编码。
echo db_password | base64
# ZGJfcGFzc3dvcmQKecho ZGJfcGFzc3dvcmQK | base64 -d
# db_password这里将 Base64 编码过后的值填入对应的 key - value 中。
# hellok8s-secret.yaml
apiVersion: v1
kind: Secret
metadata:name: hellok8s-secret
data:DB_PASSWORD: ZGJfcGFzc3dvcmQK# hellok8s.yaml
apiVersion: v1
kind: Pod
metadata:name: hellok8s-pod
spec:containers:- name: hellok8s-containerimage: guangzhengli/hellok8s:v5env:- name: DB_PASSWORDvalueFrom:secretKeyRef:name: hellok8s-secretkey: DB_PASSWORDpackage mainimport (fmtionet/httpos
)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)
}在代码中读取 DB_PASSWORD 环境变量直接返回对应字符串。Secret 的使用方法和前面教程中 ConfigMap 基本一致这里就不再过多赘述。
docker build . -t guangzhengli/hellok8s:v5docker push guangzhengli/hellok8s:v5kubectl apply -f hellok8s-secret.yamlkubectl apply -f hellok8s.yamlkubectl port-forward hellok8s-pod 3000:30009、Job 在实际的开发过程中还有一类任务是之前的资源不能满足的即一次性任务。例如常见的计算任务只需要拿到相关数据计算后得出结果即可无需一直运行。而处理这一类任务的资源就是 Job。 Job 会创建一个或者多个 Pod并将继续重试 Pod 的执行直到指定数量的 Pod 成功终止。 随着 Pod 成功结束Job 跟踪记录成功完成的 Pod 个数。 当数量达到指定的成功个数阈值时任务即 Job结束。 删除 Job 的操作会清除所创建的全部 Pod。 挂起 Job 的操作会删除 Job 的所有活跃 Pod直到 Job 被再次恢复执行。 一种简单的使用场景下你会创建一个 Job 对象以便以一种可靠的方式运行某 Pod 直到完成。 当第一个 Pod 失败或者被删除比如因为节点硬件失效或者重启时Job 对象会启动一个新的 Pod。 下面来看一个 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。
apiVersion: batch/v1
kind: Job
metadata:name: hello-job
spec:parallelism: 3completions: 5template:spec:restartPolicy: OnFailurecontainers:- name: echoimage: busyboxcommand:- /bin/shargs:- -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 命令查看日志。
kubectl apply -f hello-job.yamlkubectl get jobs
# NAME COMPLETIONS DURATION AGE
# hello-job 5/5 19s 83skubectl get pods
# NAME READY STATUS RESTARTS AGE
# hello-job--1-5gjjr 0/1 Completed 0 34s
# hello-job--1-8ffmn 0/1 Completed 0 26s
# hello-job--1-ltsvm 0/1 Completed 0 34s
# hello-job--1-mttwv 0/1 Completed 0 29s
# hello-job--1-ww2qp 0/1 Completed 0 34skubectl logs -f hello-job--1-5gjjr
# 1
# ...Job 完成时不会再创建新的 Pod不过已有的 Pod 通常也不会被删除。 保留这些 Pod 使得你可以查看已完成的 Pod 的日志输出以便检查错误、警告或者其它诊断性输出。 可以使用 kubectl 来删除 Job例如 kubectl delete -f hello-job.yaml)。当使用 kubectl 来删除 Job 时该 Job 所创建的 Pod 也会被删除。
CronJob
CronJob 可以理解为定时任务创建基于 Cron 时间调度的 Jobs。
CronJob 用于执行周期性的动作例如备份、报告生成等。 这些任务中的每一个都应该配置为周期性重复的例如每天/每周/每月一次 你可以定义任务开始执行的时间间隔。
Cron 时间表语法
# ┌───────────── 分钟 (0 - 59)
# │ ┌───────────── 小时 (0 - 23)
# │ │ ┌───────────── 月的某天 (1 - 31)
# │ │ │ ┌───────────── 月份 (1 - 12)
# │ │ │ │ ┌───────────── 周的某天 (0 - 6)周日到周一在某些系统上7 也是星期日
# │ │ │ │ │ 或者是 sunmontuewebthufrisat
# │ │ │ │ │
# │ │ │ │ │
# * * * * *用法除了需要加上 cron 表达式之外其余基本和 Job 保持一致。
apiVersion: batch/v1
kind: CronJob
metadata:name: hello-cronjob
spec:schedule: * * * * * # Every minutejobTemplate:spec:template:spec:restartPolicy: OnFailurecontainers:- name: echoimage: busyboxcommand:- /bin/shargs:- -c- for i in 9 8 7 6 5 4 3 2 1 ; do echo $i ; done使用命令和 Job 也基本保持一致这里就不过多赘述。
kubectl apply -f hello-cronjob.yaml
# cronjob.batch/hello-cronjob createdkubectl get cronjob
# NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
# hello-cronjob * * * * * False 0 none 8skubectl get pods
# NAME READY STATUS RESTARTS AGE
# hello-cronjob-27694609--1-2nmdx 0/1 Completed 0 15s10、Helm
提示后续出 简单来说就是创建chart的工具 - 添加到自己的仓库-根据文件下载 可以声明式的根据yml文件 创建pod
helm介绍
11、Others
Dashboard 提示面板管理 Dashboard 是基于网页的 Kubernetes 用户界面。 你可以使用 Dashboard 将容器应用部署到 Kubernetes 集群中也可以对容器应用排错还能管理集群资源。 你可以使用 Dashboard 获取运行在集群中的应用的概览信息也可以创建或者修改 Kubernetes 资源 如 DeploymentJobDaemonSet 等等。 例如你可以对 Deployment 实现弹性伸缩、发起滚动升级、重启 Pod 或者使用向导创建新的应用。 在本地 minikube 环境可以直接通过下面命令开启 Dashboard。更多用法可以参考官网或者自行探索。
minikube dashboardK9s
K9s 是一个基于 Terminal 的轻量级 UI可以更加轻松的观察和管理已部署的 k8s 资源。使用方式非常简单安装后输入 k9s 即可开启 Terminal Dashboard更多用法可以参考官网。 后续对于k8s的操作会持续更新