博主昵称:跳楼梯企鹅
创作初心:本博客的初心为与技术朋友们相互交流,每个人的技术都存在短板,博主也是一样,虚心求教,希望各位技术友给予指导。
博主座右铭:发现光,追随光,成为光,散发光;
博主研究方向:渗透测试、机器学习 ;
博主寄语:感谢各位技术友的支持,您的支持就是我前进的动力 ;
本篇文章分为3次分享完
前两部分已经分享了,今天来完结吧~
七·、Job
1.快速了解
Kubernetes jobs主要是针对短时和批量的工作负载。它是为了结束而运行的,而不是像deployment、replicasets、replication controllers和DaemonSets等其他对象那样持续运行。
Kubernetes Jobs会一直运行到Job中指定的任务完成。也就是说,如果pods给出退出代码0,那么Job就会退出。而在正常的Kubernetes中,无论退出代码是什么,deployment对象在终止或出现错误时都会创建新的pod,以保持deployment的理想状态。
在job运行过程中,如果托管pod的节点发生故障,Job pod将被自动重新安排到另一个节点。
2. 实例
(1)批处理任务: 比如说你想每天运行一次批处理任务,或者在指定日程中运行。它可能是像从存储库或数据库中读取文件那样,将它们分配给一个服务来处理文件。
(2)运维/ad-hoc任务: 比如你想要运行一个脚本/代码,该脚本/代码会运行一个数据库清理活动,甚至备份一个Kubernetes集群。
3.创建Kubernetes Job
使用自定义的Docker镜像创建一个job.yaml文件,参数传递给docker ENTRYPOINT脚本。 apiVersion: batch/v1 使用kubectl创建一个job.yaml文件的job kubectl apply -f job.yam 使用kubectl检查job的状态 kubectl get jobs 使用kubectl获取pod列表 kubectl get po 使用kubectl获取job pod 日志。使用你在输出中看到的Pod名称替换原本的Pod名称。 kubectl logs kubernetes-job-example-bc7s9 -f 如下输出: 并行运行多Job pods 当一个job被部署后,你可以让它在多个Pod上并行运行: completions: 6 带有那些参数的manifest: apiVersion: batch/v1 为Kubernetes Job生成随机名称 你不能从一个job manifest文件中创建多个job apiVersion: batch/v1
4.运行一次性容器
启动这个job [root@k8s-master k8s]# kubectl apply -f myjob.yml job.batch/myjob created kubectl get job 查看这个job [root@k8s-master k8s]# kubectl get job NAME COMPLETIONS DURATION AGE myjob 1/1 23s 3m45s completions为 1/1 表示成功运行了这个job kubectl get pod 查看pod的状态 [root@k8s-master k8s]# kubectl get pod NAME READY STATUS RESTARTS AGE myjob-29qlw 0/1 Completed 0 4m5s 看到 状态为Completed表示这个job已经运行完成 kubectl logs 命令查看这个 pod的日志 [root@k8s-master k8s]# kubectl logs myjob-29qlw hello k8s job!
5.job controller源码
JobController 结构 type JobController struct { // 访问 kube-apiserver 的client // 需要查询 job、pod 等元数据信息 kubeClient clientset.Interface // pod 控制器,用于创建和删除pod使用 podControl controller.PodControlInterface // 用于更新 job status updateHandler func(job *batch.Job) error // job controller 核心接口,用于 sync job syncHandler func(jobKey string) (bool, error) // job controller 在启动时会对 job & pod 先进行同步 // 用于判断是否已经对 pod 同步过 podStoreSynced cache.InformerSynced // 用于判断是否已经对 job 同步过 jobStoreSynced cache.InformerSynced // expectations cache,记录该job下pods的adds & dels次数, // 并提供接口进行调整,已达到期望值。 expectations controller.ControllerExpectationsInterface // jobLister 用于获取job元数据及根据pod的labels来匹配jobs // 该controller 会使用到的接口如下: // 1. GetPodJobs(): 用于根据pod反推jobs // 2. Get(): 根据namespace & name 获取job 元数据 jobLister batchv1listers.JobLister // podStore 提供了接口用于获取指定job下管理的所有pods podStore corelisters.PodLister // Jobs queue // job controller通过kubeClient watch jobs & pods的数据变更, // 比如add、delete、update,来操作该queue。 // 并启动相应的worker,调用syncJob处理该queue中的jobs。 queue workqueue.RateLimitingInterface // jobs的相关events,通过该recorder进行广播 recorder record.EventRecorder } startJobController() func startJobController(ctx ControllerContext) (bool, error) { // 在启动job controller之前,判断下job 是否有配置生效 // 用户可以在创建k8s clusters时,通过修改kube-apiserver --runtime-config配置想要生效的 resource if !ctx.AvailableResources[schema.GroupVersionResource{Group: "batch", Version: "v1", Resource: "jobs"}] { return false, nil } // 初始化 JobController结构,并Run // Run的时候指定了gorutinue的数量,每个gorutinue 就是一个worker go job.NewJobController( ctx.InformerFactory.Core().V1().Pods(), ctx.InformerFactory.Batch().V1().Jobs(), ctx.ClientBuilder.ClientOrDie("job-controller"), ).Run(int(ctx.ComponentConfig.JobController.ConcurrentJobSyncs), ctx.Stop) return true, nil } NewJobController() func NewJobController(podInformer coreinformers.PodInformer, jobInformer batchinformers.JobInformer, kubeClient clientset.Interface) *JobController { // 初始化event broadcaster // 用于该controller 发送job 相关的events eventBroadcaster := record.NewBroadcaster() // 注册打印event信息的function // eventBroadcaster.StartEventWatcher()会创建gorutinue并开始watch event, // 根据注册的eventHandler轮询处理每个event,这里就是通过glog.Infof打印日志 eventBroadcaster.StartLogging(glog.Infof) // EventSinkImpl 包含了一个EventInterface, 实现了Create/Update/Delete/Get/Watch/Patch..等等操作 // 这一步跟上面一样,也是通过eventBroadcaster.StartEventWatcher() 注册了EventInterface实现, // 用来从指定的eventBroadcaster接收event,并发送给指定的接收器。 // k8s event实现可以多带带进行源码分析,值得学习下。 eventBroadcaster.StartRecordingToSink(&v1core.EventSinkImpl{Interface: kubeClient.CoreV1().Events("")}) // kubernetes 内部的限流策略 // 对apiserver来说,每个controller及scheduler都是client,所以内部的限流策略也至关重要。 if kubeClient != nil && kubeClient.CoreV1().RESTClient().GetRateLimiter() != nil { metrics.RegisterMetricAndTrackRateLimiterUsage("job_controller", kubeClient.CoreV1().RESTClient().GetRateLimiter()) } // 初始化JobController jm := &JobController{ // 连接kube-apiserver的client kubeClient: kubeClient, // podControl,用于manageJob()中创建和删除pod podControl: controller.RealPodControl{ KubeClient: kubeClient, Recorder: eventBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "job-controller"}), }, // 维护的期望状态下的Pod Cache,并且提供了修正该Cache的接口 // 比如会存jobs 下pods 的adds & dels 值,并提供了接口修改这两个值。 expectations: controller.NewControllerExpectations(), // jobs queue, 后面会创建对应数量的workers 从该queue 中处理各个jobs。 queue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemExponentialFailureRateLimiter(DefaultJobBackOff, MaxJobBackOff), "job"), // event recorder,用于发送job 相关的events recorder: eventBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "job-controller"}), } // 注册jobInformer 的Add、Update、Delete 函数 // 该controller 获取到job 的Add、Update、Delete事件之后,会调用对应的function // 这些function 的核心还是去操作了上面的queue,让syncJob 处理queue 中的jobs jobInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) { jm.enqueueController(obj, true) }, UpdateFunc: jm.updateJob, DeleteFunc: func(obj interface{}) { jm.enqueueController(obj, true) }, }) // 上面结构中已经有介绍 jm.jobLister = jobInformer.Lister() jm.jobStoreSynced = jobInformer.Informer().HasSynced // 注册 podInformer 的Add、Update、Delete 函数 // job 最终是依托了pod 去运行,所以相关的pods 事件也需要关心。 // 该podInformer 会监听所有的pods 变更事件,所以函数中都会去判断该pod 的containerRef是否是“job”, // 如果是的话再更新对应的expectations & queue, 触发syncJob进行处理。 podInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: jm.addPod, UpdateFunc: jm.updatePod, DeleteFunc: jm.deletePod, }) // 上面结构中已经有介绍 jm.podStore = podInformer.Lister() jm.podStoreSynced = podInformer.Informer().HasSynced // 注册更新job status的函数 jm.updateHandler = jm.updateJobStatus // 注册sync job handler // 核心实现 jm.syncHandler = jm.syncJob return jm } Run() // Run the main goroutine responsible for watching and syncing jobs. func (jm *JobController) Run(workers int, stopCh <-chan struct{}) { defer utilruntime.HandleCrash() defer jm.queue.ShutDown() glog.Infof("Starting job controller") defer glog.Infof("Shutting down job controller") // 每次启动都会先等待Job & Pod cache 是否有同步过,即指queue是否已经同步过数据, // 因为每个worker干的活都是从queue中获取,所以只有queue有数据才应该继续往下创建worker。 if !controller.WaitForCacheSync("job", stopCh, jm.podStoreSynced, jm.jobStoreSynced) { return } // 创建指定数量的gorutinue // 每个gorutinue 执行worker,每个worker 执行完了之后sleep 1s,然后继续循环执行 for i := 0; i < workers; i++ { go wait.Until(jm.worker, time.Second, stopCh) } <-stopCh }
6.cronJob
cronJob是基于时间进行任务的定时管理:
在特定的时间点运行任务
反复在指定的时间点运行任务:比如定时进行数据库备份,定时发送电子邮件等等。
八、ConfigMap
为了解决传统容器中配置的挂载、变更、管理等问题,在k8s中引入了一个叫做configmap的资源对象,在configmap中,各个配置项都是以key-value的方式存在的,value的数据可以是一个配置文件的内容,这些配置项被保存在k8s使用的持久化存储etcd中。这样就形成了一个k8s中的配置中心,可以独立的对configmap中的数据进行修改,然后将configmap挂载到pod中进行使用,可以以env的方式,也可以以配置文件的方式在pod中进行引用,这样配置和pod就实现了解耦,都是k8s中独立的资源对象。
个人理解:configmap是k8s中的应用配置管理方案。
1. ConfigMap基础命令
kubectl create configmap test --from-file=/root/yaml/nginx.yaml #将/root/yaml/nginx.yaml文件写入configmap 名字为test(存储配置文件) kubectl create configmap test02 --from-file=/root/yaml/ #将/root/yaml/目录下的文件写入configmap,configmap 名字为test02 kubectl create configmap test01 --from-literal=MYSQL_ROOT_PASSWORD=123456 #变量储存到configmap,变量名为MYSQL_ROOT_PASSWORD,值为123456,可以跟更多变量,在尾部加--from-literal=key=value 即可 kubectl describe configmaps test #查询上面的结果
2. configmap对象
(1)定义环境变量
kubectl apply -f - <<'eof' apiVersion: v1 kind: ConfigMap metadata: name: cm-vars data: apploglevel: info appdatadir: /var/data eof
(2)执行创建configmap
[root@root ~]# kubectl apply -f - <<'eof' > apiVersion: v1 > kind: ConfigMap > metadata: > name: cm-vars > data: > apploglevel: info > appdatadir: /var/data > eof configmap/cm-vars created [root@root ~]# kubectl get cm NAME DATA AGE cm-vars 2 5s kube-root-ca.crt 1 38d [root@root ~]#
(3)查看configmap
[root@root ~]# kubectl get cm cm-vars -o yaml apiVersion: v1 data: appdatadir: /var/data apploglevel: info kind: ConfigMap metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"v1","data":{"appdatadir":"/var/data","apploglevel":"info"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"cm-vars","namespace":"default"}} creationTimestamp: "2022-01-10T07:31:05Z" managedFields: - apiVersion: v1 fieldsType: FieldsV1 fieldsV1: f:data: .: {} f:appdatadir: {} f:apploglevel: {} f:metadata: f:annotations: .: {} f:kubectl.kubernetes.io/last-applied-configuration: {} manager: kubectl-client-side-apply operation: Update time: "2022-01-10T07:31:05Z" name: cm-vars namespace: default resourceVersion: "11021769" selfLink: /api/v1/namespaces/default/configmaps/cm-vars uid: c513d39b-c128-46d3-9eb7-78da20ec47f2 [root@root ~]# kubectl describe cm cm-vars Name: cm-vars Namespace: default Labels: <none> Annotations: <none> Data ==== appdatadir: ---- /var/data apploglevel: ---- info Events: <none>
(4)使用configmap
apiVersion: v1 kind: ConfigMap metadata: name: test04 data: MYSQL_ROOT_PASSWORD: '123456' #定义一个变量,值类型为字符串,所以需要加引号 my.cnf: | [mysqld] pid-file = /var/run/mysqld/mysqld.pid socket = /var/run/mysqld/mysqld.sock datadir = /var/lib/mysql character-set-server = utf8 log-error = /var/log/mysqld.log # 中继日志 relay-log=mysql-relay-bin replicate-wild-ignore-table=mysql.% replicate-wild-ignore-table=test.% replicate-wild-ignore-table=information_schema.% --- kind: Deployment apiVersion: apps/v1 metadata: name: mysql spec: selector: matchLabels: app: mysql template: metadata: labels: app: mysql spec: containers: - name: mysql image: mysql:5.7 imagePullPolicy: IfNotPresent volumeMounts: - mountPath: /opt #挂载到那个目录 name: test command: - sh - -c - sleep 100 volumes: - name: test #存储卷的名称 configMap: name: test04 #configmap名字 items: - key: my.cnf #configmap 内文件 path: my.cnf #configmap挂载到容器内的相对路径
九、Secrets
secret是k8s中用来存储敏感认证信息的一种重要资源,大致可以分为三种类型:docker-registry
,generic
和tls
,从名称上就可以看出来,分别用于存储镜像仓库认证信息,一般信息和证书信息。其中generic类型的最常用,比较典型的就是用来存放数据库的认证信息。
说白了就是一种安全机制
1.Secret 有三种类型
(1)Service Account :用来访问 Kubernetes API,由 Kubernetes 自动创建,用于被 serviceaccount 引用。serviceaccout 创建时 Kubernetes 会默认创建对应的 secret。Pod 如果使用了 serviceaccount,对应的 secret 会自动挂载到 Pod 的 /run/secrets/kubernetes.io/serviceaccount 目录中。
(2)Opaque :base64编码格式的Secret,用来存储密码、密钥等
(3)kubernetes.io/dockerconfigjson :用来存储私有 docker registry 的认证信息
2.创建secret
[root@root pod]# kubectl create secret --help Create a secret using specified subcommand. Available Commands: docker-registry Create a secret for use with a Docker registry generic Create a secret from a local file, directory or literal value tls Create a TLS secret Usage: kubectl create secret [flags] [options] Use "kubectl <command> --help" for more information about a given command. Use "kubectl options" for a list of global command-line options (applies to all commands).