下篇1:将 ConfigMap 中的键值对作为容器的环境变量
Posted ttropsstack
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了下篇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
开发示例应用
- goweb项目目录结构
[root@workhost goweb]# tree
.
├── Dockerfile
├── go.mod
├── main.go
├── README.md
└── static
└── login.html
- 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 服务。
- 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>
实战:以使用“容器的环境变量”的方式
- 制作镜像
编写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
- 测试
[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,且能正常访问:
- 创建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。
- 创建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 的值注入到容器的环境变量中的功能。
- 进入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 #
- 完整的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
本文转载于WX公众号:不背锅运维(喜欢的盆友关注我们):https://mp.weixin.qq.com/s/14zOTnmUSK39PHj8t9m3mQ
BigQuery:将数组中的键值对转换为列
【中文标题】BigQuery:将数组中的键值对转换为列【英文标题】:BigQuery: Converting key-value pairs in Array to columns 【发布时间】:2020-11-02 03:31:43 【问题描述】:我引用了这个post 并希望将event_params
字段中选定的键值对转换为列。我的桌子是这样的:
| user_id | event_params.key | event_params.value.string_value |
+---------+------------------+---------------------------------+
| 1 | k1 | v11 |
| +------------------+---------------------------------+
| | k2 | v12 |
| +------------------+---------------------------------+
| | k3 | v13 |
+---------+------------------+---------------------------------+
| 1 | k1 | v21 |
| +------------------+---------------------------------+
| | k2 | v22 |
| +------------------+---------------------------------+
| | k3 | v23 |
+---------+------------------+---------------------------------+
| 2 | k1 | v31 |
| +------------------+---------------------------------+
| | k2 | v32 |
| +------------------+---------------------------------+
| | k3 | v33 |
每个大行在event_params
字段内有任意 N 行,并且每个大行可以重复,因为它可以由同一用户生成。我想保留这种重复。
我想要的最终结果:
| user_id | k1 | k3 |
+---------+-----+-----+
| 1 | v11 | v13 |
+---------+-----+-----+
| 1 | v21 | v23 |
+---------+-----+-----+
| 2 | v31 | v33 |
到目前为止我的查询:
SELECT
user_id,
IF(event_params.key = 'k1', event_params.value.string_value, NULL) AS k1,
IF(event_params.key = 'k3', event_params.value.string_value, NULL) AS k3,
FROM `my-proj-id.analytics_xxxxx.events_20201030`
, UNNEST(event_params) AS event_params
WHERE event_name='my-event-name'
为简洁起见,上表省略了event_name
。
我当前的实现导致NULL
出现在整个k3
列中,我认为这可能是由于UNNEST
造成的,并且没有一个未嵌套的行会同时包含k1 和k3。如何转换为上述我想要的最终结果?
注意:我想用标准 SQL 编写
【问题讨论】:
【参考方案1】:以下是 BigQuery 标准 SQL
#standardSQL
select user_id,
(select value.string_value from t.event_params where key = 'k1') as k1,
(select value.string_value from t.event_params where key = 'k3') as k3
from `my-proj-id.analytics_xxxxx.events_20201030` t
如果应用于您问题中的样本数据 - 输出是
【讨论】:
【参考方案2】:您可以在FROM
子句中使用LEFT JOIN
s 执行此操作:
SELECT e.user_id,
event_k1.value.string_value AS k1,
event_k3.value.string_value AS k3
FROM `my-proj-id.analytics_xxxxx.events_20201030` e LEFT JOIN
UNNEST(e.event_params) event_k1
ON event_k1.key = 'k1' LEFT JOIN
UNNEST(e.event_params) event_k3
ON event_k3.key = 'k3'
WHERE e.event_name = 'my-event-name';
【讨论】:
以上是关于下篇1:将 ConfigMap 中的键值对作为容器的环境变量的主要内容,如果未能解决你的问题,请参考以下文章