美文网首页K8S容器编排最佳实践
K8S容器编排之ConfigMap 用于动态应用程序的实践

K8S容器编排之ConfigMap 用于动态应用程序的实践

作者: 云爬虫技术研究笔记 | 来源:发表于2019-01-27 23:43 被阅读2386次

    导言:在 Kubernetes 中,ConfigMap 是允许管理员将配置组件与镜像内容解耦,使容器化应用程序产生可移植性的一种资源。ConfigMap 可以与 Kubernetes Pod 一起使用,用于动态添加或更改容器中的使用文件。本文将阐述 Kubernetes ConfigMap 如何利用动态应用程序的方法来解决轻量级文件服务器部署到 Kubernetes 集群中的问题。

    ConfigMap 概览

    生产环境中很多应用程序的配置可能需要通过配置文件、命令行参数和环境变量的组合来完成。这些配置应该从镜像中解耦,通过这种方式来保持容器化应用程序的可移植性。在 Kubernetes 1.2 版本以后,研发人员引入 ConfigMap 来处理这种类型的配置数据。

    简单来说,ConfigMap 是容器的配置管理。在容器运行时,ConfigMap 把配置文件、命令行参数、环境变量、端口号和其他配置组件绑定到 Pod 的容器和系统组件上,同时将应用的代码和配置区分开。从数据角度来看,ConfigMap 的类型只是键值对。从应用角度来看,管理员可以从不同角度来配置它。

    在 Pod 中使用 ConfigMap 大致有以下三种方式:

    • 将 ConfigMap 中的数据设置为环境变量;
    • 将 ConfigMap 中的数据设置为命令行参数;
    • 将 ConfigMap 作为文件或目录挂载。
      另外,由于应用会从环境变量和包含配置数据的文件中读取配置信息,所以 ConfigMap 是可以支持这两种读取方式的。

    创配置 ConfigMap 的注意事项

    众所周知,ConfigMapSecret 很相似。但是,ConfigMap 主要用来存储和共享非敏感、未加密的配置信息。Secret 是用来存储敏感信息(例如:密码)。除了这个大家都了解的注意事项外,在配置 ConfigMap 时还要注意以下 4 点:

    • ConfigMap 必须在被 Pod 使用之前创建;
    • Pod 只能使用在同一 Namespace 中的 ConfigMap;
    • ConfigMap 大小的配额是一个已经设置好的功能;
    • Kubelet 只支持 API 服务器中的 Pod 使用 ConfigMap。
      注:API 服务器中的 Pod 包括用 Kubectl 创建的 Pod、间接通过 replication controller 创建的 Pod,不包括通过 Kubelet 的 –manifest-url 标志创建的 Pod,也不包括从它的 REST API 创建的 Pod。

    ConfigMap 用于动态应用程序的实践

    需要解决的问题

    作为 Kubernetes 安装程序的一部分,很多人希望可以将轻量级文件服务器部署到 Kubernetes 集群中以此处理默认(root - path)入口请求。并且,我认为如果我们可以编辑 index.html 和 CSS 文件而不必重新部署应用程序。

    为了解决这个用例,我们决定构建一个 Golang 应用程序,将其部分文件系统映射到 Kubernetes ConfigMap 资源中。

    Golang Fileserver

    文件服务器应用程序的设计非常简单,它仅用于提供静态内容。这种方式可以帮助 Kubernetes 用户使用入口功能。

    package main
    import (
    “log”
    “net/http”
    )
    func main() {
    fs := http.FileServer(http.Dir(“html”))
    http.Handle(“/”, fs)
    log.Println(“Listening…”)
    http.ListenAndServe(“:8080”, nil)
    }
    

    应用程序使用以下 Dockerfile 内容构建容器镜像。它是一个两阶段的 Dockerfile,首先在 Alpine 容器中执行 Golang 构建,然后将已编译的二进制和空 helm 目录复制到最终的 scratch-based 镜像上。

    # build stage  
    FROM golang:alpine AS builder  
    WORKDIR /usr/local/go/src  
    COPY  main.go .  
    RUN CGO_ENABLED=0 GOOS=linux go build -o main .  
    
    
    # final stage  
    FROM scratch  
    WORKDIR /  
    COPY --from=builder /usr/local/go/src/main main  
    COPY html html  
    EXPOSE 8080  
    ENTRYPOINT ["/main"]
    

    在 Golang 应用程序中使用 scratch 容器来部署 Golang 容器是一种更安全、更轻量级的方法。

    部署和运行

    我使用 make 来自动化 Docker 操作。以下是此应用程序的 Makefile 。

    VERSION?= 0.0.1   
    NAME?=“ingress-default”   
    AUTHOR?=“Jimmy Ray”   
    PORT_EXT?= 8080   
    PORT_INT?= 8080    
    NO_CACHE?= true   
    
    
    .PHONY:build run stop clean   
    
    
    build:   
    docker build -f scratch.dockerfile.-t $(NAME)\:$(VERSION) -  no-cache = $(NO_CACHE)
    
    
    run:   docker   
    run --name $(NAME)-d -p $(PORT_EXT):$(PORT_INT)$(NAME) \:$(VERSION)&& docker ps -a --format“{{.ID}} \ t {{.Names}}”| grep $(NAME)   
    
    
    stop:   
    docker rm $$(docker stop $$(docker ps) -a -q --filter“ancestor = $(NAME):$(VERSION)” -  format =“{{.ID}}”))   
    
    clean:   
    @rm -f main   
    
    DEFAULT:build
    

    我们可以使用 make 消除重复任务之间的可变性。有了上述的 Makefile,在将测试的应用程序部署到 Kubernetes 之前,我们可以在 Docker 中构建和运行应用程序。

    配置 Kubernetes

    对于此解决方案,我们需要配置 Kubernetes Namespace、ConfigMap、Deployment、Service 和 Ingress。我们通过使用 kubectl apply -f 的方法来完成此操作(这是对 Kubernetes 集群资源应用更改的声明式方法)。

    下面是我们将 munge 的 Kubernetes 资源的 YAML 文件。

    apiVersion: v1  
    kind: Namespace  
    metadata:  
      name: ingress-default 
      labels:  
        app: ingress-default  
    ---  
    kind: ConfigMap  
    apiVersion: v1  
    metadata:  
      name: ingress-default-static-files  
      namespace: ingress-default   
      labels:  
        app: ingress-default   
    data:  
      index.html: |  
        <!doctype html>  
        <html>  
          <head>  
            <meta charset="utf-8">  
            <title>Cluster Ingress Index</title>  
            <link rel="stylesheet" href="main.css">  
          </head>  
          <body>  
            <table class="class1">  
              <tr>  
                <td class="class2">Kubernetes Platform</td>  
              </tr>  
              <tr>  
                <td class="class1">  
                  <table class="class3">  
                    <tr><td><h1>Cluster Ingress Index</h1></td></tr>  
                  </table>  
                </td>  
              </tr>  
              <tr>  
                <td>  
                  <table class="class3">  
                    <tr>  
                    <td>  
                       <h2>The following are links to this cluster's ingress resources:</h2>  
                      </td>  
                    </tr>  
                    <tr>  
                    <td class="class4">  
                        <a href="https://<ROOT_INGRESS_PATH>" target="_blank">Root Ingress</a><br/>  
                        <a href="https://<OTHER_INGRESS_PATH>" target="_blank">Other Ingress</a><br/>   
                     </td>  
                   </tr>  
                  </table>  
                </td>  
              </tr>  
             </table>  
          </body>  
        </html>  
      main.css: |  
        body {  
          background-color: rgb(224,224,224);  
          font-family: Verdana, Arial, Helvetica, sans-serif;  
          font-size: 100%;  
        }  
        .class1 {  
      ... 
        }  
        .class2 {  
      ... 
        }  
        .class3 {  
      ... 
        }  
        .class4 {  
         ...
        }   
    ---  
    apiVersion: apps/v1  
    kind: Deployment  
    metadata:  
      labels:  
        app: ingress-default   
      name: ingress-default  
      namespace: ingress-default 
    spec:  
      selector:  
        matchLabels:  
          app: ingress-default  
      replicas: 1  
      template:  
        metadata:  
          labels:  
            app: ingress-default    
          name: ingress-default  
        spec:  
          containers:  
            - name: ingress-default  
              image: <IMAGE_REGISTRY_REPO_TAG>  
              imagePullPolicy: Always  
              resources:  
                limits:  
                  cpu: 100m  
                  memory: 10Mi  
                requests:  
                  cpu: 100m  
                  memory: 10Mi  
              volumeMounts:  
                - readOnly: true  
                  mountPath: html  
                  name: html-files  
          volumes:  
            - name: html-files  
              configMap:  
                name: ingress-default-static-files  
    ---  
    kind: Service  
    apiVersion: v1  
    metadata:  
      name: ingress-default  
      namespace: ingress-default  
      labels:  
        app: ingress-default  
    spec:  
      selector:  
        app: ingress-default  
      ports:  
      - name: http  
        protocol: TCP  
        port: 80  
        targetPort: 8080  
    ---  
    apiVersion: extensions/v1beta1  
    kind: Ingress  
    metadata:  
      name: default-ingress  
      namespace: ingress-default  
      annotations:   
        nginx.ingress.kubernetes.io/rewrite-target: /  
        kubernetes.io/ingress.class: "nginx"    
      labels:  
        app: ingress-default  
    spec:  
      rules:  
      - http:  
          paths:  
          - path: /  
            backend:  
              serviceName: ingress-default  
              servicePort: 80
    

    正如在 YAML 中的:

    ingress-default-static-files

    我们可以知道,ConfigMap 包含index.html 和 main.css 文件的内容。通过编辑或替换此 ConfigMap,我们可以更改在 Golang 文件服务器应用程序中的文件。

    使用 ConfigMap 作为卷

    在 Docker 和 Kubernetes 的中,卷用于解决两个问题:

    • 需要持久化的文件系统;
    • 需要在容器之间共享的文件系统。
      现在,我们将已部署在容器中的卷映射到 ConfigMap 资源中。在下面的代码段中,被配置的 html-files 卷可能被 Pod 中的所有容器使用。

    卷会将数据配置映射到 ConfigMap 中的 ingress-default-static-files 上。

    ...volumes:  
         - name: html-files  
           configMap:  
             name: ingress-default-static-files…
    

    在 Pod 级别配置卷后,我们将配置的卷装入容器中。将此卷的挂载映射到在 Pod 中配置的 html-files 卷上。通过此映射,应用程序容器现在可以访问 ConfigMap 中的两个文件:html/index.html 和 html/mian.css。

    ...volumeMounts:  
         - readOnly: true  
           mountPath: html  
           name: html-files 
    

    当在 Kubernetes 集群中启动 Golang 应用程序时,ingress-default 会在 NGINX 入口控制器中配置上游规则。生成的路径将通过 NGINX 入口控制器将集群边缘连接到ingress-default 服务上。此服务指向 Golang 文件服务的 app Pod 中。在运行时,它为 ingress 控制器的根路径上的默认 Web 应用程序提供服务。如果需要更改此网页,我们只需要 edit/replace ConfigMap。

    结语

    容器编排的一个关键好处是,它承诺消除多个容器工作负载所需的“无差异的繁重工作”。通过使用 Kubernetes 声明性配置功能(如 ConfigMap),可以提高应用程序部署和更改集群状态的效率与速度。我们通过将 ConfigMap 资源作为已安装的卷,使用正在运行的容器,可以从容器中抽象配置和内容,减少对镜像重构和重新部署容器的需求。

    相关文章

      网友评论

        本文标题:K8S容器编排之ConfigMap 用于动态应用程序的实践

        本文链接:https://www.haomeiwen.com/subject/hwkojqtx.html