k8s volume 挂载踩坑
source link: https://studygolang.com/articles/25829
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
实践之中,犯错是最好的财富,探究犯错的原因并总结记录,你就捡到了这笔财富。努力吧,慢慢来。
场景一:挂载配置文件到应用程序所在的目录
应用程序是一个简单地 HTTP Server,其启动的时候会去读取当前目录下的 config.yaml
文件。
应用程序代码
package main import ( "fmt" "io" "io/ioutil" "log" "net/http" "gopkg.in/yaml.v2" ) type config struct { Port string `yaml:"port"` } var c = new(config) func init() { fContent, err := ioutil.ReadFile("config.yaml") if err != nil { log.Fatal(err) } if err = yaml.Unmarshal(fContent, c); err != nil { log.Fatal(err) } } func main() { handlerFunc := func(w http.ResponseWriter, r *http.Request) { io.WriteString(w, "Hello !") } http.HandleFunc("/", handlerFunc) log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", c.Port), nil)) }
配置文件
port: 8080
Dockerfile
FROM centos COPY server /home/server # 工作目录一定要指定,因为代码里读 config.yaml 写的是相对路径 WORKDIR /home CMD /home/server
然后开始编写 k8s 部署 YAML 文件
# httpserver 依赖的配置文件 apiVersion: v1 data: config.yaml: | port: 8080 kind: ConfigMap metadata: name: httpserver-config namespace: default --- # httpserver deployment apiVersion: apps/v1 kind: Deployment metadata: name: httpserver labels: app: httpserver spec: replicas: 1 selector: matchLabels: app: httpserver template: metadata: labels: app: httpserver spec: volumes: - name: config configMap: name: httpserver-config containers: - name: bookstore image: uhub.service.ucloud.cn/wangkai/httpserver:v0.0.1 ports: - containerPort: 8080 # 把配置文件挂载到 /home 目录去 volumeMounts: - name: config mountPath: /home
执行这些 YAML 配置后,我们会发现程序没有启动起来,报错: /bin/sh: /home/server: No such file or directory
。原因很简单,我们把 config volume
挂载到 /home
目录后覆盖了该目录下的文件。以至于
此时 /home
目录下只有 config.yaml
,原先的二进制文件被覆盖掉了
。
解决的办法是:
-
把配置文件挂载到其他目录,比如
/data
,然后修改应用程序代码,去/data
目录读。 -
添加
subPath
配置,subPath
可以指明使用volume
的一个子目录,而不是其整个根目录。
第一种办法 曲线救国 ,我们使用第二种 k8s 自身的解决方案来解决问题,只需要修改几行配置即可。
spec: volumes: - name: config configMap: name: httpserver-config containers: - name: bookstore image: uhub.service.ucloud.cn/wangkai/httpserver:v0.0.1 ports: - containerPort: 9090 volumeMounts: - name: config # 在目录地址后加上文件名,与 subPath 中指定的文件名相同 mountPath: /home/config.yaml # 使用 config volume 的 config.yaml 文件,而不是整个 volume subPath: config.yaml
修改后再执行 kubectl apply -f xx.yaml
就可以运行了, describe
Pod 查看,能看到挂载情况:
Mounts: /home/config.yaml from config (rw,path="config.yaml") /var/run/secrets/kubernetes.io/serviceaccount from default-token-jp596 (ro)
场景二:同时挂 ConfigMap & Secret 到同一目录下
有些场景,我们的配置文件可能不止一个,我们的应用程序要读取当前目录下的多个配置文件,比如既有 ConfigMap
也有 Secret
。Docker 是不允许多个 Volume 挂到同一目录的,此类情况也可以通过 subPath
得到解决。
apiVersion: apps/v1 kind: Deployment metadata: name: httpserver labels: app: httpserver spec: replicas: 1 selector: matchLabels: app: httpserver template: metadata: labels: app: httpserver spec: volumes: - name: db-secret secret: secretName: db-secret - name: config configMap: name: httpserver-config containers: - name: httpserver image: uhub.service.ucloud.cn/wangkai/httpserver:v0.0.1 ports: - containerPort: 9090 volumeMounts: - name: config mountPath: /home/config.yaml # 只挂载 volume 的 config.yaml 而不是整个 volume subPath: config.yaml - name: db-secret mountPath: /home/secret.yaml # 只挂载 volume 的 secret.yaml 而不是整个 volume subPath: secret.yaml
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK