下篇1:将 ConfigMap 中的键值对作为容器的环境变量

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 下篇1:将 ConfigMap 中的键值对作为容器的环境变量

写在开篇

继续接上篇,《一文了解K8S的ConfigMap》。上篇聊过,官方文档中提到的可以使用下面4种方式来使用 ConfigMap 配置 Pod 中的容器:

  • 容器的环境变量:可以将 ConfigMap 中的键值对作为容器的环境变量。
  • 在只读卷里面添加一个文件,让应用来读取:可以将 ConfigMap 中的内容作为一个只读卷挂载到 Pod 中的容器内部,然后在容器内读取挂载的文件。
  • 编写代码在 Pod 中运行,使用 Kubernetes API 来读取 ConfigMap:可以在 Pod 中运行自定义代码,使用 Kubernetes API 来读取 ConfigMap 中的内容。
  • 在容器命令和参数内:可以在容器的启动命令中通过引用环境变量的方式来使用 ConfigMap。

为了控制篇幅,计划分4篇进行分享,本篇分享以使用“容器的环境变量”的方式进行实战。 关于使用ConfigMap的更多详情,可参考官方文档:https://kubernetes.io/zh-cn/docs/concepts/configuration/configmap/#using-configmaps

开发示例应用

  1. goweb项目目录结构
[root@workhost goweb]# tree
.
├── Dockerfile
├── go.mod
├── main.go
├── README.md
└── static
    └── login.html
  1. main.go
package main
import (
        "fmt"
        "log"
        "net/http"
        "os"
        "text/template"
)
type Message struct {
        Msg string
}
func home(w http.ResponseWriter, r *http.Request) {
        if r.Method == "GET" {
                w.Header().Set("Location", "/login")
                w.WriteHeader(http.StatusFound)
        }
}
func login(w http.ResponseWriter, r *http.Request) {
        t, _ := template.ParseFiles("./static/login.html")
        if r.Method == "GET" {
                t.Execute(w, nil)
        }
}
func main() {
        http.HandleFunc("/", home)
        http.HandleFunc("/login", login)
        args := os.Args
        if args[1] == "-p" {
                port := args[2]
                listenAddr := fmt.Sprintf(":%v", port)
                log.Println("ListenAndserve", listenAddr)
                err := http.ListenAndServe(listenAddr, nil)
                if err != nil {
                        log.Println(err)
                }
        }
}

本次代码在上次的基础上做了点小改造:接受命令行参数,使用 os.Args 获取程序运行时的参数。如果传入的参数中包含 -p,则说明需要指定监听的端口,将端口值读取出来并使用 http.ListenAndServe 启动 HTTP 服务。

  1. login.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Login K8S</title>
    <style>
      body {
        background-color: #f2f2f2;
        font-family: Arial, sans-serif;
      }
      #login-box {
        background-color: #fff;
        border-radius: 5px;
        box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
        margin: 100px auto;
        max-width: 400px;
        padding: 20px;
      }
      h1 {
        font-size: 24px;
        margin: 0 0 20px;
        text-align: center;
      }
      label {
        display: block;
        font-size: 14px;
        font-weight: bold;
        margin-bottom: 5px;
      }
      input[type="text"],
      input[type="password"] {
        border-radius: 3px;
        border: 1px solid #ccc;
        box-sizing: border-box;
        font-size: 14px;
        padding: 10px;
        width: 100%;
      }
      input[type="submit"] {
        background-color: #007bff;
        border: none;
        border-radius: 3px;
        color: #fff;
        cursor: pointer;
        font-size: 14px;
        padding: 10px;
        width: 100%;
      }
      input[type="submit"]:hover {
        background-color: #0069d9;
      }
      .error-message {
        color: #dc3545;
        font-size: 14px;
        margin: 10px 0;
        text-align: center;
      }
    </style>
  </head>
  <body>
    <div id="login-box">
      <h1>容器云管理平台</h1>
      <form>
        <label for="username">账号:</label>
        <input type="text" id="username" name="username">
        <label for="password">密码:</label>
        <input type="password" id="password" name="password">
        <input type="submit" value="登录">
      </form>
      <div class="error-message"></div>
    </div>
    <script>
      const form = document.querySelector('form');
      const errorMessage = document.querySelector('.error-message');
      form.addEventListener('submit', function(event) {
        event.preventDefault();
        const username = document.getElementById('username').value;
        const password = document.getElementById('password').value;
        if (username === '' || password === '') {
          errorMessage.textContent = 'Please enter a username and password.';
        } else if (username !== 'admin' || password !== 'password') {
          errorMessage.textContent = 'Incorrect username or password.';
        } else {
          alert('Login successful!');
        }
      });
    </script>
  </body>
</html>

实战:以使用“容器的环境变量”的方式

  1. 制作镜像

编写Dockerfile:

FROM alpine:latest
WORKDIR /app
COPY static /app/static
COPY main /app
ENV PORT 80 # 设置默认端口号为80,这个值将在容器启动时被覆盖
CMD ["/bin/sh", "-c", "./main -p $PORT"]

构建镜像和推送到私有harbor:

docker build -t 192.168.11.254:8081/webdemo/goweb:20230515v2 .
docker push 192.168.11.254:8081/webdemo/goweb:20230515v2
  1. 测试
[root@workhost goweb]# docker run --rm -it -p 80:9090 -e PORT=9090 192.168.11.254:8081/webdemo/goweb:20230515v2
2023/05/15 02:08:43 ListenAndserve :9090

使用 -p 参数将本地主机的 80 端口映射到容器内部的 9090 端口,使用 -e 参数设置环境变量 PORT 的值为 9090,可以正常启动,说明在启动时已经覆盖掉了默认端口80,且能正常访问:

  1. 创建configmap
kubectl create configmap goweb --from-literal=port=9091

执行命令后将会创建一个名为 goweb 的 ConfigMap,其中包含一个名为 port 的键,值为 9091。这样,在 Pod 中使用 $PORT 环境变量时,就可以将其设置为 9091。

说明:--from-literal=port=9091 表示要将 port 这个键的值设置为 9091,这里使用 --from-literal 标志表示将文本作为字面量值创建 ConfigMap。

  1. 创建pod
apiVersion: v1
kind: Pod
metadata:
  name: goweb
spec:
  containers:
  - name: goweb
    image: 192.168.11.254:8081/webdemo/goweb:20230515v2
    env:
    - name: PORT
      valueFrom:
        configMapKeyRef:
          name: goweb
          key: port

上面yaml中,通过设置 env 字段,将 ConfigMap 中的 port 键值对作为环境变量注入到容器中的应用程序中。使用了 valueFrom 字段指定了 ConfigMap 的名称和键,从而将 ConfigMap 中的 port 值注入到容器的 PORT 环境变量中。这样,在容器启动后,应用程序就可以通过读取 PORT 环境变量的值来获取应该监听的端口,实现了将 ConfigMap 的值注入到容器的环境变量中的功能。

  1. 进入pod验证
[root@k8s-b-master ~]# kubectl get pod
NAME    READY   STATUS    RESTARTS   AGE
goweb   1/1     Running   0          29s
[root@k8s-b-master ~]# kubectl exec -it goweb -- sh
/app # ps
PID   USER     TIME  COMMAND
    1 root      0:00 ./main -p 9091
   11 root      0:00 sh
   17 root      0:00 ps
/app #
  1. 完整的yaml
apiVersion: v1
metadata:
  name: goweb
data:
  port: "9091"
kind: ConfigMap
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: goweb
  name: goweb
spec:
  replicas: 3
  selector:
    matchLabels:
      app: goweb
  template:
    metadata:
      labels:
        app: goweb
    spec:
      containers:
        - name: goweb
          image: 192.168.11.254:8081/webdemo/goweb:20230515v2
          env:
          - name: PORT
            valueFrom:
              configMapKeyRef:
                name: goweb
                key: port


相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
云原生实践公开课
课程大纲 开篇:如何学习并实践云原生技术 基础篇: 5 步上手 Kubernetes 进阶篇:生产环境下的 K8s 实践 相关的阿里云产品:容器服务&nbsp;ACK 容器服务&nbsp;Kubernetes&nbsp;版(简称&nbsp;ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情:&nbsp;https://www.aliyun.com/product/kubernetes
相关文章
|
JSON 网络协议 开发工具
对已有的docker容器添加新的目录映射, 端口映射,环境变量,dns等
docker容器已经建立并运行, 需要在已有容器上添加新的目录映射,端口映射,环境变量等
1973 0
|
6天前
|
Java 数据库连接 Docker
【Docker 专栏】Docker 容器内环境变量的管理与使用
【5月更文挑战第9天】本文介绍了Docker容器中环境变量的管理与使用,环境变量用于传递配置信息和设置应用运行环境。设置方法包括在Dockerfile中使用`ENV`指令或在启动容器时通过`-e`参数设定。应用可直接访问环境变量或在脚本中使用。环境变量作用包括传递配置、设置运行环境和动态调整应用行为。使用时注意变量名称和值的合法性、保密性和覆盖问题。理解并熟练运用环境变量能提升Docker技术的使用效率和软件部署质量。
【Docker 专栏】Docker 容器内环境变量的管理与使用
|
6月前
|
存储 缓存 Java
Golang Map:高效的键值对容器
Golang Map:高效的键值对容器
|
9月前
|
消息中间件 Java Kafka
Hyperledger Fabric 通道配置文件和容器环境变量详解
Fabric 节点的主配置路径为 FABRIC_CFG_PATH 环境变量所指向路径(默认为 /etc/hyperledger/fabric)。在不显式指定配置路径时,会尝试从主配置路径下查找相关的配置文件。
229 0
|
Kubernetes 监控 Java
如何灵活的更改微服务容器运行时的堆内存大小及环境变量
SpringBoot微服务打包容器启动运行时就会加载打包时设置的Jvm参数,当上线后监控到内存不足时需要调整参数时就要重新打包升级版本等一系列繁琐操作,那能不能只需要更改配置重启就能解决问题呢
171 0
|
运维 API 容器
3.3. [kustz] 注入 ConfigMap 和 Secrets 到容器环境变量
3.3. [kustz] 注入 ConfigMap 和 Secrets 到容器环境变量
211 0
3.3. [kustz] 注入 ConfigMap 和 Secrets 到容器环境变量
|
容器
Kubernetes----Pod配置容器的环境变量
Kubernetes----Pod配置容器的环境变量
603 0
|
Linux Docker 容器
Docker - 解决重新进入容器后,环境变量失效的问题
Docker - 解决重新进入容器后,环境变量失效的问题
670 0
|
6天前
|
监控 Kubernetes Docker
【Docker 专栏】Docker 容器内应用的健康检查与自动恢复
【5月更文挑战第9天】本文探讨了Docker容器中应用的健康检查与自动恢复,强调其对应用稳定性和系统性能的重要性。健康检查包括进程、端口和应用特定检查,而自动恢复则涉及重启容器和重新部署。Docker原生及第三方工具(如Kubernetes)提供了相关功能。配置检查需考虑检查频率、应用特性和监控告警。案例分析展示了实际操作,未来发展趋势将趋向更智能和高效的检查恢复机制。
【Docker 专栏】Docker 容器内应用的健康检查与自动恢复
|
2天前
|
Prometheus 监控 Cloud Native
构建高效稳定的Docker容器监控体系
【5月更文挑战第13天】在微服务架构和容器化部署日益普及的背景下,对Docker容器的监控变得尤为重要。本文将探讨一种构建高效稳定Docker容器监控体系的方法,通过集成Prometheus和cAdvisor工具,实现对容器资源使用情况、性能指标和运行状态的实时监控。同时,结合Grafana进行数据可视化,为运维人员提供直观的分析界面,以便及时发现和解决潜在问题,保障系统的高可用性和稳定性。
15 6