# 如何把文件传到容器中？
在云容器引擎（CCE）中部署业务应用时，应用通常需要读取配置文件、数据库密码、证书等数据才能正常运行。例如，一个Web应用需要读取数据库连接地址和端口，一个微服务需要加载Nginx配置文件，一个安全组件需要读取TLS证书。这些数据如果直接硬编码在容器镜像中，每次修改都需要重新构建镜像，效率低且不灵活。
CCE基于Kubernetes，提供了多种向Pod中传递数据的方式，使您可以在不重新构建镜像的前提下，灵活地将配置信息、敏感数据和持久化数据注入到容器中。本文将介绍常见的几种数据传递方式及其适用场景，帮助您根据业务需求选择合适的方法。
#### 如何选择数据传递方式
不同场景下推荐的数据传递方式如下：
| 数据类型          | 推荐方式       | 数据是否持久化 | 典型场景                    |
|:---|:---|:---|:---|
| 非敏感配置参数（少量）   | 环境变量       | 否      | 数据库连接地址、超时时间等简单参数        |
| 非敏感配置文件        | ConfigMap | 否       | Nginx配置文件、应用配置文件          |
| 敏感数据（密码、密钥）    | Secret       | 否       | 数据库密码、TLS证书、API密钥         |
| 需持久化的大体量数据   | PVC       | 是        | 数据库数据、日志文件、上传文件           |
| Pod内多容器共享临时数据 | emptyDir    | 否      | Init容器与主容器之间的数据传递        |
| 调试或特殊场景       | hostPath   | 是        | 访问节点上的Docker socket或系统文件 |
   
#### 通过环境变量传递数据
环境变量适合传递少量的简单配置参数，如数据库连接地址、端口号等。您可以直接在Pod定义中设置环境变量的值，也可以引用ConfigMap或Secret中的数据作为环境变量。
**直接设置环境变量**
以下示例将数据库地址和端口通过环境变量直接注入到容器中：
```
apiVersion: apps/v1
kind: Deployment
metadata:
  name: env-deployment
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: nginx:latest
        env:
        - name: DB_HOST
          value: "192.168.1.100"
        - name: DB_PORT
          value: "3306"
      imagePullSecrets:
      - name: default-secret
```
容器启动后，应用程序可通过读取环境变量 DB_HOST 和 DB_PORT 获取数据库连接信息。
**从ConfigMap引用环境变量**
如果配置参数需要被多个工作负载共享或集中管理，建议先创建ConfigMap，再在工作负载中引用。
1. 创建ConfigMap。 
   ```
   apiVersion: v1
   kind: ConfigMap
   metadata:
     name: app-config
     namespace: default
   data:
     DB_HOST: "192.168.1.100"
     DB_PORT: "3306"
     LOG_LEVEL: "debug"
   ```
   
   
2. 在工作负载中引用ConfigMap作为环境变量。 
   ```
   apiVersion: apps/v1
   kind: Deployment
   metadata:
     name: configmap-env-deployment
     namespace: default
   spec:
     replicas: 2
     selector:
       matchLabels:
         app: myapp
     template:
       metadata:
         labels:
           app: myapp
       spec:
         containers:
         - name: myapp
           image: nginx:latest
           envFrom:
           - configMapRef:
               name: app-config
         imagePullSecrets:
         - name: default-secret
   ```
   使用envFrom可以将ConfigMap中的所有键值对一次性注入为环境变量。如果只需引用部分键值，可使用env + configMapKeyRef的方式：
   ```
   env:
           - name: DB_HOST
             valueFrom:
               configMapKeyRef:
                 name: app-config
                 key: DB_HOST
   ```
   
   
3. 工作负载创建完成后，可通过以下命令验证环境变量是否注入成功： 
   ```
   kubectl exec configmap-env-deployment-<pod-name-suffix> -- env | grep DB_HOST
   ```
   其中\<pod-name-suffix\>为Pod名称后缀，可通过**kubectl get pods -l app=myapp**查看。若回显显示DB_HOST=192.168.1.100，说明环境变量注入成功。
   
   
 
#### 通过ConfigMap挂载为配置文件
当您需要将配置文件（如Nginx配置、应用YAML文件）注入到容器中时，可以将ConfigMap挂载为文件到指定目录。
1. 创建包含配置文件内容的ConfigMap。 
   ```
   apiVersion: v1
   kind: ConfigMap
   metadata:
     name: nginx-config
     namespace: default
   data:
     nginx.conf: |
       server {
           listen 80;
           server_name localhost;
           location / {
               proxy_pass http://backend:8080;
           }
       }
   ```
   
   
2. 创建工作负载并挂载ConfigMap为文件。 
   ```
   apiVersion: apps/v1
   kind: Deployment
   metadata:
     name: configmap-volume-deployment
     namespace: default
   spec:
     replicas: 2
     selector:
       matchLabels:
         app: nginx
     template:
       metadata:
         labels:
           app: nginx
       spec:
         imagePullSecrets:
         - name: default-secret
         containers:
         - name: nginx
           image: nginx:latest
           volumeMounts:
           - name: config-volume
             mountPath: /etc/nginx/conf.d
         volumes:
         - name: config-volume
           configMap:
             name: nginx-config
   ```
   上述配置将ConfigMap中的nginx.conf文件挂载到容器的/etc/nginx/conf.d目录下，容器内的Nginx会自动读取该配置文件。
   
   
3. 通过以下命令查看挂载的配置文件内容： 
   ```
   kubectl exec configmap-volume-deployment-<pod-name-suffix> -- cat /etc/nginx/conf.d/nginx.conf
   ```
   若回显显示ConfigMap中定义的Nginx配置内容，说明挂载成功。
   
   
 
#### 通过Secret传递敏感数据
Secret用于存储密码、密钥、证书等敏感信息。Secret中的数据以Base64编码存储，在使用时自动解码为明文注入到容器中。
1. 创建Secret。 
   以下命令创建一个包含数据库用户名和密码的Secret：
   ```
   kubectl create secret generic db-secret \
     --from-literal=username=admin \
     --from-literal=password=xxxxx
   ```
   也可以通过YAML文件创建：
   ```
   apiVersion: v1
   kind: Secret
   metadata:
     name: db-secret
     namespace: default
   type: Opaque
   data:
     username: YWRtaW4=
     password: TXlQxxxx
   ```
   ![](https://support.huaweicloud.com/cce_faq/public_sys-resources/note_3.0-zh-cn.png)
   YAML方式创建Secret时，data字段的值必须是Base64编码后的字符串。可使用 **echo -n 'admin' \| base64** 命令进行编码。命令行方式（**kubectl create secret**）创建时会自动编码，无需手动转换。
   
   
2. 在工作负载中使用Secret。 
   **在工作负载中以环境变量方式引用Secret** ：
   ```
   apiVersion: apps/v1
   kind: Deployment
   metadata:
     name: secret-env-deployment
     namespace: default
   spec:
     replicas: 2
     selector:
       matchLabels:
         app: myapp
     template:
       metadata:
         labels:
           app: myapp
       spec:
         imagePullSecrets:
         - name: default-secret
         containers:
         - name: myapp
           image: nginx:latest
           env:
           - name: DB_USERNAME
             valueFrom:
               secretKeyRef:
                 name: db-secret
                 key: username
           - name: DB_PASSWORD
             valueFrom:
               secretKeyRef:
                 name: db-secret
                 key: password
   ```
   **在工作负载中以文件方式挂载Secret**
   如果需要将证书文件挂载到容器中（如TLS证书），可以将Secret挂载为文件。
   ```
   apiVersion: apps/v1
   kind: Deployment
   metadata:
     name: secret-volume-deployment
     namespace: default
   spec:
     replicas: 2
     selector:
       matchLabels:
         app: myapp
     template:
       metadata:
         labels:
           app: myapp
       spec:
         imagePullSecrets:
         - name: default-secret
         containers:
         - name: myapp
           image: nginx:latest
           volumeMounts:
           - name: secret-volume
             mountPath: /etc/ssl
             readOnly: true
         volumes:
         - name: secret-volume
           secret:
             secretName: tls-secret
   ```
   
   
3. 通过以下命令验证Secret是否注入成功： 
   ```
   kubectl exec secret-env-deployment-<pod-name-suffix> -- env | grep DB_PASSWORD
   ```
   若回显显示DB_PASSWORD=xxxxx，说明Secret已成功注入。
   
   
 
#### 通过PVC挂载持久化存储
当需要将大体量数据持久化存储到Pod中，且Pod删除后数据仍需保留时，建议使用PVC挂载持久卷。CCE支持多种存储类型，包括云硬盘（EVS）、弹性文件服务（SFS Turbo）、对象存储（OBS）等。
1. 创建PVC。以下示例创建一个使用云硬盘（EVS）存储的PVC，通过CCE提供的 csi-disk StorageClass动态创建云硬盘： 
   ```
   apiVersion: v1
   kind: PersistentVolumeClaim
   metadata:
     name: data-pvc
     namespace: default
     annotations:
       everest.io/disk-volume-type: SSD
       everest.io/volume-reclaim-policy: retain
     labels:
       failure-domain.beta.kubernetes.io/region: <your_region>   # 替换为您待部署应用的节点所在的区域
       failure-domain.beta.kubernetes.io/zone: <your_zone>       # 替换为您待部署应用的节点所在的可用区
   spec:
     accessModes:
     - ReadWriteOnce
     resources:
       requests:
         storage: 20Gi
     storageClassName: csi-disk
   ```
   
   
2. 创建工作负载并挂载PVC。 
   ```
   apiVersion: apps/v1
   kind: Deployment
   metadata:
     name: pvc-deployment
     namespace: default
   spec:
     replicas: 1
     selector:
       matchLabels:
         app: myapp
     template:
       metadata:
         labels:
           app: myapp
       spec:
         imagePullSecrets:
         - name: default-secret
         containers:
         - name: myapp
           image: nginx:latest
           volumeMounts:
           - name: data-volume
             mountPath: /data
         volumes:
         - name: data-volume
           persistentVolumeClaim:
             claimName: data-pvc
   ```
   上述配置将PVC挂载到容器的 /data 目录，应用程序可将数据写入该目录，数据会持久化到后端存储中，即使Pod被删除，数据也不会丢失。
   ![](https://support.huaweicloud.com/cce_faq/public_sys-resources/note_3.0-zh-cn.png)
   使用云硬盘（EVS）存储时，PVC的访问模式为ReadWriteOnce，仅支持单节点挂载。如果工作负载replicas大于1，多个副本会争抢同一块云硬盘导致挂载失败。多副本场景请使用SFS Turbo（csi-sfsturbo）或OBS（csi-obs），该类型支持ReadWriteMany多节点读写。
   
   
3. 通过以下命令验证PVC是否挂载成功： 
   ```
   kubectl get pvc data-pvc
   ```
   若STATUS显示为 Bound，说明PVC已成功绑定PV。再执行以下命令验证Pod中是否可读写数据：
   ```
   kubectl exec pvc-deployment-<pod-name-suffix> -- sh -c "echo 'test data' > /data/test.txt && cat /data/test.txt"
   ```
   若回显显示 test data，说明PVC挂载成功且数据可正常读写。
   
   
 
#### 通过emptyDir共享临时数据
emptyDir用于Pod内多个容器之间共享临时数据。典型场景是Init容器准备数据后，主容器读取使用。
```
apiVersion: apps/v1
kind: Deployment
metadata:
  name: emptydir-deployment
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      imagePullSecrets:
      - name: default-secret
      volumes:
      - name: shared-data
        emptyDir: {}
      initContainers:
      - name: init-container
        image: busybox:latest
        command: ["/bin/sh", "-c", "echo 'config data' > /shared/config.txt"]
        volumeMounts:
        - name: shared-data
          mountPath: /shared
      containers:
      - name: main-container
        image: nginx:latest
        volumeMounts:
        - name: shared-data
          mountPath: /usr/share/nginx/html
```
上述示例中，Init容器将配置数据写入 /shared/config.txt，主容器从 /usr/share/nginx/html 目录读取该文件。emptyDir的生命周期与Pod一致，Pod删除后数据随之清除。
您可以通过以下命令验证数据是否共享成功：
```
kubectl exec emptydir-deployment-<pod-name-suffix> -- cat /usr/share/nginx/html/config.txt
```
若回显显示 config data，说明数据共享成功。
#### 通过hostPath挂载节点文件
hostPath将节点（宿主机）上的文件或目录直接挂载到Pod中。典型场景包括：容器需要访问节点的Docker socket（如监控容器运行时）、读取节点系统文件（如 /proc、/sys）、或与节点上运行的其他服务共享数据。
![](https://support.huaweicloud.com/cce_faq/public_sys-resources/caution_3.0-zh-cn.png)
hostPath直接访问节点文件系统，存在安全风险。Pod被调度到不同节点时，挂载的数据也不同，可能导致行为不一致。生产环境请优先使用PVC，仅在调试或特殊场景下使用hostPath。
```
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hostpath-deployment
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      imagePullSecrets:
      - name: default-secret
      containers:
      - name: myapp
        image: nginx:latest
        volumeMounts:
        - name: host-data
          mountPath: /host-data
      volumes:
      - name: host-data
        hostPath:
          path: /data/node # 节点上的目录或文件路径
          type: Directory # 挂载类型，指定路径的存在性校验规则：Directory（必须存在且为目录）、File（必须存在且为文件）、DirectoryOrCreate（不存在则创建目录）、FileOrCreate（不存在则创建文件）、""（不校验，向后兼容）
```
您可以通过以下命令验证hostPath是否挂载成功：
```
kubectl exec hostpath-deployment-<pod-name-suffix> -- ls /host-data
```
若回显显示节点 /data/node 目录下的文件列表，说明挂载成功。也可通过以下命令确认Pod所在节点，再到该节点上验证数据一致性：
```
kubectl get pod hostpath-deployment-<pod-name-suffix> -o wide
```
查看NODE列确认Pod调度的节点，登录该节点执行 **ls /data/node** 对比内容。
#### 相关文档
- [存储概述](https://support.huaweicloud.com/usermanual-cce/cce_10_0307.md)：了解CCE支持的存储类型（EVS、SFS、OBS）及CSI存储架构。
- [存储基础知识](https://support.huaweicloud.com/usermanual-cce/cce_10_0378.md)：了解Kubernetes Volume机制及emptyDir、hostPath等存储卷基础概念。
- [通过kubectl连接集群](https://support.huaweicloud.com/usermanual-cce/cce_10_0107.md)：如需通过kubectl操作集群，请先参考此文档完成连接配置。
- [使用配置项](https://support.huaweicloud.com/usermanual-cce/cce_10_0015.md)：了解ConfigMap的创建及在工作负载环境变量、数据卷中的使用方法。
- [使用密钥](https://support.huaweicloud.com/usermanual-cce/cce_10_0016.md)：了解Secret的创建及在工作负载环境变量、数据卷中的使用方法。
 
