• 【云原生】Kubernetes核心技术(下)


    博主昵称:跳楼梯企鹅
    博主主页面链接:博主主页传送门

    博主专栏页面连接:专栏传送门--网路安全技术
    创作初心:本博客的初心为与技术朋友们相互交流,每个人的技术都存在短板,博主也是一样,虚心求教,希望各位技术友给予指导。
    博主座右铭:发现光,追随光,成为光,散发光;
    博主研究方向:渗透测试、机器学习 ;
    博主寄语:感谢各位技术友的支持,您的支持就是我前进的动力 ;

    本篇文章分为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

    1. 使用自定义的Docker镜像创建一个job.yaml文件,参数传递给docker ENTRYPOINT脚本。
    2. apiVersion: batch/v1
    3. 使用kubectl创建一个job.yaml文件的job
    4. kubectl apply -f job.yam
    5. 使用kubectl检查job的状态
    6. kubectl get jobs
    7. 使用kubectl获取pod列表
    8. kubectl get po
    9. 使用kubectl获取job pod 日志。使用你在输出中看到的Pod名称替换原本的Pod名称。
    10. kubectl logs kubernetes-job-example-bc7s9 -f
    11. 如下输出:
    12. 并行运行多Job pods
    13. 当一个job被部署后,你可以让它在多个Pod上并行运行:
    14. completions: 6
    15. 带有那些参数的manifest:
    16. apiVersion: batch/v1
    17. 为Kubernetes Job生成随机名称
    18. 你不能从一个job manifest文件中创建多个job
    19. apiVersion: batch/v1

    4.运行一次性容器

    1. 启动这个job
    2. [root@k8s-master k8s]# kubectl apply -f myjob.yml
    3. job.batch/myjob created
    4. kubectl get job 查看这个job
    5. [root@k8s-master k8s]# kubectl get job
    6. NAME COMPLETIONS DURATION AGE
    7. myjob 1/1 23s 3m45s
    8. completions为 1/1 表示成功运行了这个job
    9. kubectl get pod 查看pod的状态
    10. [root@k8s-master k8s]# kubectl get pod
    11. NAME READY STATUS RESTARTS AGE
    12. myjob-29qlw 0/1 Completed 0 4m5s
    13. 看到 状态为Completed表示这个job已经运行完成
    14. kubectl logs 命令查看这个 pod的日志
    15. [root@k8s-master k8s]# kubectl logs myjob-29qlw
    16. hello k8s job!

    5.job controller源码

    1. JobController 结构
    2. type JobController struct {
    3. // 访问 kube-apiserver 的client
    4. // 需要查询 job、pod 等元数据信息
    5. kubeClient clientset.Interface
    6. // pod 控制器,用于创建和删除pod使用
    7. podControl controller.PodControlInterface
    8. // 用于更新 job status
    9. updateHandler func(job *batch.Job) error
    10. // job controller 核心接口,用于 sync job
    11. syncHandler func(jobKey string) (bool, error)
    12. // job controller 在启动时会对 job & pod 先进行同步
    13. // 用于判断是否已经对 pod 同步过
    14. podStoreSynced cache.InformerSynced
    15. // 用于判断是否已经对 job 同步过
    16. jobStoreSynced cache.InformerSynced
    17. // expectations cache,记录该job下pods的adds & dels次数,
    18. // 并提供接口进行调整,已达到期望值。
    19. expectations controller.ControllerExpectationsInterface
    20. // jobLister 用于获取job元数据及根据pod的labels来匹配jobs
    21. // 该controller 会使用到的接口如下:
    22. // 1. GetPodJobs(): 用于根据pod反推jobs
    23. // 2. Get(): 根据namespace & name 获取job 元数据
    24. jobLister batchv1listers.JobLister
    25. // podStore 提供了接口用于获取指定job下管理的所有pods
    26. podStore corelisters.PodLister
    27. // Jobs queue
    28. // job controller通过kubeClient watch jobs & pods的数据变更,
    29. // 比如add、delete、update,来操作该queue。
    30. // 并启动相应的worker,调用syncJob处理该queue中的jobs。
    31. queue workqueue.RateLimitingInterface
    32. // jobs的相关events,通过该recorder进行广播
    33. recorder record.EventRecorder
    34. }
    35. startJobController()
    36. func startJobController(ctx ControllerContext) (bool, error) {
    37. // 在启动job controller之前,判断下job 是否有配置生效
    38. // 用户可以在创建k8s clusters时,通过修改kube-apiserver --runtime-config配置想要生效的 resource
    39. if !ctx.AvailableResources[schema.GroupVersionResource{Group: "batch", Version: "v1", Resource: "jobs"}] {
    40. return false, nil
    41. }
    42. // 初始化 JobController结构,并Run
    43. // Run的时候指定了gorutinue的数量,每个gorutinue 就是一个worker
    44. go job.NewJobController(
    45. ctx.InformerFactory.Core().V1().Pods(),
    46. ctx.InformerFactory.Batch().V1().Jobs(),
    47. ctx.ClientBuilder.ClientOrDie("job-controller"),
    48. ).Run(int(ctx.ComponentConfig.JobController.ConcurrentJobSyncs), ctx.Stop)
    49. return true, nil
    50. }
    51. NewJobController()
    52. func NewJobController(podInformer coreinformers.PodInformer, jobInformer batchinformers.JobInformer, kubeClient clientset.Interface) *JobController {
    53. // 初始化event broadcaster
    54. // 用于该controller 发送job 相关的events
    55. eventBroadcaster := record.NewBroadcaster()
    56. // 注册打印event信息的function
    57. // eventBroadcaster.StartEventWatcher()会创建gorutinue并开始watch event,
    58. // 根据注册的eventHandler轮询处理每个event,这里就是通过glog.Infof打印日志
    59. eventBroadcaster.StartLogging(glog.Infof)
    60. // EventSinkImpl 包含了一个EventInterface, 实现了Create/Update/Delete/Get/Watch/Patch..等等操作
    61. // 这一步跟上面一样,也是通过eventBroadcaster.StartEventWatcher() 注册了EventInterface实现,
    62. // 用来从指定的eventBroadcaster接收event,并发送给指定的接收器。
    63. // k8s event实现可以多带带进行源码分析,值得学习下。
    64. eventBroadcaster.StartRecordingToSink(&v1core.EventSinkImpl{Interface: kubeClient.CoreV1().Events("")})
    65. // kubernetes 内部的限流策略
    66. // 对apiserver来说,每个controller及scheduler都是client,所以内部的限流策略也至关重要。
    67. if kubeClient != nil && kubeClient.CoreV1().RESTClient().GetRateLimiter() != nil {
    68. metrics.RegisterMetricAndTrackRateLimiterUsage("job_controller", kubeClient.CoreV1().RESTClient().GetRateLimiter())
    69. }
    70. // 初始化JobController
    71. jm := &JobController{
    72. // 连接kube-apiserver的client
    73. kubeClient: kubeClient,
    74. // podControl,用于manageJob()中创建和删除pod
    75. podControl: controller.RealPodControl{
    76. KubeClient: kubeClient,
    77. Recorder: eventBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "job-controller"}),
    78. },
    79. // 维护的期望状态下的Pod Cache,并且提供了修正该Cache的接口
    80. // 比如会存jobs 下pods 的adds & dels 值,并提供了接口修改这两个值。
    81. expectations: controller.NewControllerExpectations(),
    82. // jobs queue, 后面会创建对应数量的workers 从该queue 中处理各个jobs。
    83. queue: workqueue.NewNamedRateLimitingQueue(workqueue.NewItemExponentialFailureRateLimiter(DefaultJobBackOff, MaxJobBackOff), "job"),
    84. // event recorder,用于发送job 相关的events
    85. recorder: eventBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "job-controller"}),
    86. }
    87. // 注册jobInformer 的Add、Update、Delete 函数
    88. // 该controller 获取到job 的Add、Update、Delete事件之后,会调用对应的function
    89. // 这些function 的核心还是去操作了上面的queue,让syncJob 处理queue 中的jobs
    90. jobInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
    91. AddFunc: func(obj interface{}) {
    92. jm.enqueueController(obj, true)
    93. },
    94. UpdateFunc: jm.updateJob,
    95. DeleteFunc: func(obj interface{}) {
    96. jm.enqueueController(obj, true)
    97. },
    98. })
    99. // 上面结构中已经有介绍
    100. jm.jobLister = jobInformer.Lister()
    101. jm.jobStoreSynced = jobInformer.Informer().HasSynced
    102. // 注册 podInformer 的Add、Update、Delete 函数
    103. // job 最终是依托了pod 去运行,所以相关的pods 事件也需要关心。
    104. // 该podInformer 会监听所有的pods 变更事件,所以函数中都会去判断该pod 的containerRef是否是“job”,
    105. // 如果是的话再更新对应的expectations & queue, 触发syncJob进行处理。
    106. podInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
    107. AddFunc: jm.addPod,
    108. UpdateFunc: jm.updatePod,
    109. DeleteFunc: jm.deletePod,
    110. })
    111. // 上面结构中已经有介绍
    112. jm.podStore = podInformer.Lister()
    113. jm.podStoreSynced = podInformer.Informer().HasSynced
    114. // 注册更新job status的函数
    115. jm.updateHandler = jm.updateJobStatus
    116. // 注册sync job handler
    117. // 核心实现
    118. jm.syncHandler = jm.syncJob
    119. return jm
    120. }
    121. Run()
    122. // Run the main goroutine responsible for watching and syncing jobs.
    123. func (jm *JobController) Run(workers int, stopCh <-chan struct{}) {
    124. defer utilruntime.HandleCrash()
    125. defer jm.queue.ShutDown()
    126. glog.Infof("Starting job controller")
    127. defer glog.Infof("Shutting down job controller")
    128. // 每次启动都会先等待Job & Pod cache 是否有同步过,即指queue是否已经同步过数据,
    129. // 因为每个worker干的活都是从queue中获取,所以只有queue有数据才应该继续往下创建worker。
    130. if !controller.WaitForCacheSync("job", stopCh, jm.podStoreSynced, jm.jobStoreSynced) {
    131. return
    132. }
    133. // 创建指定数量的gorutinue
    134. // 每个gorutinue 执行worker,每个worker 执行完了之后sleep 1s,然后继续循环执行
    135. for i := 0; i < workers; i++ {
    136. go wait.Until(jm.worker, time.Second, stopCh)
    137. }
    138. <-stopCh
    139. }

     6.cronJob

    cronJob是基于时间进行任务的定时管理:

    在特定的时间点运行任务

    反复在指定的时间点运行任务:比如定时进行数据库备份,定时发送电子邮件等等。

    八、ConfigMap

        为了解决传统容器中配置的挂载、变更、管理等问题,在k8s中引入了一个叫做configmap的资源对象,在configmap中,各个配置项都是以key-value的方式存在的,value的数据可以是一个配置文件的内容,这些配置项被保存在k8s使用的持久化存储etcd中。这样就形成了一个k8s中的配置中心,可以独立的对configmap中的数据进行修改,然后将configmap挂载到pod中进行使用,可以以env的方式,也可以以配置文件的方式在pod中进行引用,这样配置和pod就实现了解耦,都是k8s中独立的资源对象。

    个人理解:configmap是k8s中的应用配置管理方案。

    1. ConfigMap基础命令

    1. kubectl create configmap test --from-file=/root/yaml/nginx.yaml
    2. #将/root/yaml/nginx.yaml文件写入configmap 名字为test(存储配置文件)
    3. kubectl create configmap test02 --from-file=/root/yaml/
    4. #将/root/yaml/目录下的文件写入configmap,configmap 名字为test02
    5. kubectl create configmap test01 --from-literal=MYSQL_ROOT_PASSWORD=123456
    6. #变量储存到configmap,变量名为MYSQL_ROOT_PASSWORD,值为123456,可以跟更多变量,在尾部加--from-literal=key=value 即可
    7. kubectl describe configmaps test
    8. #查询上面的结果

    2. configmap对象

    (1)定义环境变量

    1. kubectl apply -f - <<'eof'
    2. apiVersion: v1
    3. kind: ConfigMap
    4. metadata:
    5. name: cm-vars
    6. data:
    7. apploglevel: info
    8. appdatadir: /var/data
    9. eof

     (2)执行创建configmap

    1. [root@root ~]# kubectl apply -f - <<'eof'
    2. > apiVersion: v1
    3. > kind: ConfigMap
    4. > metadata:
    5. > name: cm-vars
    6. > data:
    7. > apploglevel: info
    8. > appdatadir: /var/data
    9. > eof
    10. configmap/cm-vars created
    11. [root@root ~]# kubectl get cm
    12. NAME DATA AGE
    13. cm-vars 2 5s
    14. kube-root-ca.crt 1 38d
    15. [root@root ~]#

     (3)查看configmap

    1. [root@root ~]# kubectl get cm cm-vars -o yaml
    2. apiVersion: v1
    3. data:
    4. appdatadir: /var/data
    5. apploglevel: info
    6. kind: ConfigMap
    7. metadata:
    8. annotations:
    9. kubectl.kubernetes.io/last-applied-configuration: |
    10. {"apiVersion":"v1","data":{"appdatadir":"/var/data","apploglevel":"info"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"cm-vars","namespace":"default"}}
    11. creationTimestamp: "2022-01-10T07:31:05Z"
    12. managedFields:
    13. - apiVersion: v1
    14. fieldsType: FieldsV1
    15. fieldsV1:
    16. f:data:
    17. .: {}
    18. f:appdatadir: {}
    19. f:apploglevel: {}
    20. f:metadata:
    21. f:annotations:
    22. .: {}
    23. f:kubectl.kubernetes.io/last-applied-configuration: {}
    24. manager: kubectl-client-side-apply
    25. operation: Update
    26. time: "2022-01-10T07:31:05Z"
    27. name: cm-vars
    28. namespace: default
    29. resourceVersion: "11021769"
    30. selfLink: /api/v1/namespaces/default/configmaps/cm-vars
    31. uid: c513d39b-c128-46d3-9eb7-78da20ec47f2
    32. [root@root ~]# kubectl describe cm cm-vars
    33. Name: cm-vars
    34. Namespace: default
    35. Labels:
    36. Annotations:
    37. Data
    38. ====
    39. appdatadir:
    40. ----
    41. /var/data
    42. apploglevel:
    43. ----
    44. info
    45. Events:

     (4)使用configmap

    1. apiVersion: v1
    2. kind: ConfigMap
    3. metadata:
    4. name: test04
    5. data:
    6. MYSQL_ROOT_PASSWORD: '123456'
    7. #定义一个变量,值类型为字符串,所以需要加引号
    8. my.cnf: |
    9. [mysqld]
    10. pid-file = /var/run/mysqld/mysqld.pid
    11. socket = /var/run/mysqld/mysqld.sock
    12. datadir = /var/lib/mysql
    13. character-set-server = utf8
    14. log-error = /var/log/mysqld.log
    15. # 中继日志
    16. relay-log=mysql-relay-bin
    17. replicate-wild-ignore-table=mysql.%
    18. replicate-wild-ignore-table=test.%
    19. replicate-wild-ignore-table=information_schema.%
    20. ---
    21. kind: Deployment
    22. apiVersion: apps/v1
    23. metadata:
    24. name: mysql
    25. spec:
    26. selector:
    27. matchLabels:
    28. app: mysql
    29. template:
    30. metadata:
    31. labels:
    32. app: mysql
    33. spec:
    34. containers:
    35. - name: mysql
    36. image: mysql:5.7
    37. imagePullPolicy: IfNotPresent
    38. volumeMounts:
    39. - mountPath: /opt #挂载到那个目录
    40. name: test
    41. command:
    42. - sh
    43. - -c
    44. - sleep 100
    45. volumes:
    46. - name: test #存储卷的名称
    47. configMap:
    48. name: test04 #configmap名字
    49. items:
    50. - key: my.cnf #configmap 内文件
    51. path: my.cnf #configmap挂载到容器内的相对路径

    九、Secrets

    secret是k8s中用来存储敏感认证信息的一种重要资源,大致可以分为三种类型:docker-registrygenerictls,从名称上就可以看出来,分别用于存储镜像仓库认证信息,一般信息和证书信息。其中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

    1. [root@root pod]# kubectl create secret --help
    2. Create a secret using specified subcommand.
    3. Available Commands:
    4. docker-registry Create a secret for use with a Docker registry
    5. generic Create a secret from a local file, directory or literal value
    6. tls Create a TLS secret
    7. Usage:
    8. kubectl create secret [flags] [options]
    9. Use "kubectl --help" for more information about a given command.
    10. Use "kubectl options" for a list of global command-line options (applies to all
    11. commands).

      

  • 相关阅读:
    Java“牵手”淘宝店铺商品列表页数据采集+淘宝店铺商品上传接口,淘宝API接口申请指南
    第三范式
    现货伦敦金分析中如何应用支撑与压力位
    嵌入式Linux驱动开发(I2C专题)(一)
    查看当前所有的数据库
    为什么调用父类构造函数,super 必须是构造函数内的第一条语句?
    Docker从认识到实践再到底层原理(六-2)|Docker容器操作实例
    项目实战-day1.0
    Vue学习之--------脚手架的分析、Ref属性、Props配置(2022/7/28)
    [OtterCTF 2018] 电子取证
  • 原文地址:https://blog.csdn.net/weixin_50481708/article/details/126863663