为Pod配置ServiceAccount:实战POD内应用以API方式读取ConfigMap

写在开篇

在之前的分享中,还有遗留的实战内容没有作出分享,也就是为Pod配置ServiceAccount:

  1. 创建ServiceAccount
  2. 创建Role:定义所需的权限
  3. 创建RoleBinding,将ServiceAccount和Role关联起来
  4. 将ServiceAccount对象分配给Pod

其实,在实战这个内容之前,且已经将涉及到的前置知识点作了分享,可参考如下3篇:

本篇实战场景:开发示例应用,该应用运行在集群内POD中,并通过访问K8S API读取业务相关配置参数,且配置保存在configmap资源对象中。下面模拟了几个业务应用程序假设需要使用到参数:

说明
MaxConn 500 最大连接数
MinConn 100 最小连接数
CleanCacheTime 300s 清理缓存时间
UploadDataTime 86400s 上传数据时间

准备工作

使用kubectl命令创建名称空间和configmap

kubectl create ns goweb
kubectl create configmap gowebcm --from-literal=MaxConn=500 --from-literal=MinConn=100 --from-literal=CleanCacheTime=300s --from-literal=UploadDataTime=86400s -n goweb

对应的yaml:

apiVersion: v1
kind: Namespace
metadata:
  name: goweb
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: gowebcm
  namespace: goweb
data:
  CleanCacheTime: 300s
  MaxConn: "500"
  MinConn: "100"
  UploadDataTime: 86400s
[root@k8s-b-master ~]# kubectl get configmap -n goweb
NAME               DATA   AGE
gowebcm            4      107s

示例应用代码

下面这段代码的功能是从 Kubernetes 的 ConfigMap 中获取数据,并通过一个简单的 HTTP 服务器将数据展示在网页上:

package main

import (
 "context"
 "fmt"
 "log"
 "net/http"
 "sync"

 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 "k8s.io/client-go/kubernetes"
 "k8s.io/client-go/rest"
)

var Data []map[string]string

func getConfigMapData() {
    // 如果要使用集群外身份验证,请取消以下注释
 // var kubeconfig *string
 // if home := homedir.HomeDir(); home != "" {
 //  kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(可选)kubeconfig 文件的绝对路径")
 // } else {
 //  kubeconfig = flag.String("kubeconfig", "", "kubeconfig 文件的绝对路径")
 // }
 // config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
 // if err != nil {
 //  panic(err.Error())
 // }

    // 当前使用集群内身份验证
 config, err := rest.InClusterConfig()
 if err != nil {
  panic(err.Error())
 }

 // 创建 clientset
 clientset, err := kubernetes.NewForConfig(config)
 if err != nil {
  panic(err.Error())
 }

 configMap, err := clientset.CoreV1().ConfigMaps("goweb").Get(context.TODO(), "gowebcm", metav1.GetOptions{})
 if err != nil {
  panic(err.Error())
 }

 data := configMap.Data
 Data = append(Data, data)
}

func home(w http.ResponseWriter, r *http.Request) {
 // 构建 HTML 表格字符串
 html := `
  <!DOCTYPE html>
  <html>
  <head>
   <title>ConfigMap</title>
   <style>
    table {
     width: 100%;
     border-collapse: collapse;
     border: 1px solid #ddd;
    }

    th, td {
     padding: 10px;
     border: 1px solid #ddd;
    }
   </style>
  </head>
  <body>
   <h1>从ConfigMap读取的数据:</h1>
   <table>
 `


 for _, v := range Data {
  for key, value := range v {
   html += fmt.Sprintf("<tr><td>%v</td><td>%v</td></tr>", key, value)
  }
 }
 html += `
   </table>
  </body>
  </html>
 `

 // 设置响应头的 Content-Type 为 text/html
 w.Header().Set("Content-Type""text/html; charset=utf-8")
 // 将 HTML 写入响应体
 fmt.Fprint(w, html)
}

func startWeb() {
 http.HandleFunc("/", home)
 err := http.ListenAndServe(":80"nil)
 if err != nil {
  log.Println(err)
 }

}

func main() {
 var wg sync.WaitGroup
 wg.Add(2)
 go getConfigMapData()
 go startWeb()
 wg.Wait()
}

编译代码:

go mod tidy
GOOS=linux go build -o ./app .

Dockerfile内容:

FROM debian
COPY ./app /app
ENTRYPOINT /app

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

docker build -t 192.168.11.254:8081/webdemo/goweb:20230530v1 .
docker push 192.168.11.254:8081/webdemo/goweb:20230530v1

创建Pod,并为其配置使用指定的ServiceAccount启动

  1. 创建ServiceAccount

命令:

kubectl create serviceaccount goweb-sa -n goweb

对应的yaml:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: goweb-sa
  namespace: goweb
  1. 创建Role,定义所需的权限

命令:

kubectl create role goweb-role --verb=get --verb=list --verb=watch --namespace=goweb --resource=configmaps --resource-name=gowebcm

对应的yaml:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: goweb-role
  namespace: goweb
rules:
- apiGroups:
  - ""
  resourceNames:
  - gowebcm
  resources:
  - configmaps
  verbs:
  - get
  - list
  - watch
  1. 创建RoleBinding,将ServiceAccount和Role关联起来

命令:

kubectl create rolebinding goweb-rolebinding --role=goweb-role --serviceaccount=goweb:goweb-sa --namespace=goweb

对应的yaml:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: goweb-rolebinding
  namespace: goweb
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: goweb-role
subjects:
- kind: ServiceAccount
  name: goweb-sa
  namespace: goweb
  1. 创建Pod,将ServiceAccount对象分配给Pod
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: goweb
  name: goweb
  namespace: goweb
spec:
  replicas: 3
  selector:
    matchLabels:
      app: goweb
  template:
    metadata:
      labels:
        app: goweb
    spec:
      serviceAccountName: goweb-sa # 这里是关键
      containers:
      - name: goweb
        image: 192.168.11.254:8081/webdemo/goweb:20230530v1
        imagePullPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: goweb
  name: goweb
  namespace: goweb
spec:
  ports:
  - name: http-port
    port: 5678
    protocol: TCP
    targetPort: 80
    nodePort: 30080
  selector:
    app: goweb
  type: NodePort
  1. 暴露后访问
为Pod配置ServiceAccount:实战POD内应用以API方式读取ConfigMap

如果POD没有指定ServiceAccount启动会怎么样

也就是在deployment中注释掉以下内容:

# serviceAccountName: goweb-sa 

删掉之前的,并添加完注释后,再次创建后,看看接下来发生的情况:

[root@k8s-b-master ~]# kubectl get pod -n goweb
NAME                     READY   STATUS   RESTARTS      AGE
goweb-5d455dd849-5gnnp   0/1     Error    2 (16s ago)   18s
goweb-5d455dd849-76pkw   0/1     Error    2 (16s ago)   18s
goweb-5d455dd849-pn5dl   0/1     Error    2 (16s ago)   18s

# 看pod里容器内log
[root@k8s-b-master ~]# kubectl logs goweb-5d455dd849-5gnnp -n goweb
panic: configmaps "gowebcm" is forbidden: User "system:serviceaccount:goweb:default" cannot get resource "configmaps" in API group "" in the namespace "goweb"

goroutine 6 [running]:
main.getConfigMapData()
        /data/project/gocode/src/goweb/main.go:44 +0x13b
created by main.main
        /data/project/gocode/src/goweb/main.go:104 +0x45
[root@k8s-b-master ~]

通过查看log发现,这个错误表明名为 “gowebcm” 的 ConfigMap 对于位于 “goweb” 命名空间中的 “default” 服务账户而言是被禁止的资源。k8s使用访问控制规则来限制不同服务账户对资源的访问权限。所以,想要访问gowebcm,必须要使用刚才创建好的服务账号goweb-sa。


原文始发于微信公众号(不背锅运维):为Pod配置ServiceAccount:实战POD内应用以API方式读取ConfigMap

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/149456.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!