侧边栏壁纸
  • 累计撰写 51 篇文章
  • 累计创建 23 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

K8s Pod 和 Service 3

zhanjie.me
2020-11-11 / 0 评论 / 0 点赞 / 1 阅读 / 0 字

3.1 Secret 简介

kubernetes 的 Secret 对象可以存储和管理敏感信息,比如 passwords、OAuth tokens、以及 ssh keys 等。把敏感信息存储到 Secret 对象中会比放到 Pod 的定义文件或是容器镜像中更加安全、灵活,使用 Secret 对象可以更好的控制数据的使用方式,并且减少意外泄露的风险。

不仅用户可以创建 Secret 对象,kubernetes 系统也会创建一些 Secret 对象。

Secret 被创建以后,可以使用 3 种方式使用它:

  • 创建 Pod 时,通过为 Pod 指定 Service Account 自动使用该 Secret
  • 通过挂载该 Secret 到 Pod 来使用它
  • 在 Docker 镜像下载时使用,通过指定 Pod 的 spc.ImagePullSecrets 来引用它

在存储数据的时候,如何从 ConfigMap 和 Secret 这两者之间进行选择呢?

  • 使用 ConfigMap 存储非敏感的配置信息
  • 使用 Secret 存储敏感的配置信息
  • 如果配置文件既包含敏感信息、又包含非敏感信息,依然选择 Secret 进行存储

Secret 和 ConfigMap 对比,既有相同点、也有不同点,列表如下:

相同点:

  • 存储数据都属于 key-value 键值对形式
  • 属于某个特定的 namespace
  • 可以导出到环境变量
  • 可以通过目录/文件形式挂载(支持挂载所有 key 和部分 key)

不同点:

  • Secret 可以被 ServerAccount 关联使用
  • Secret 可以存储 Register 的鉴权信息,用于 ImagePullSecret 参数中,用于拉取私有仓库的镜像
  • Secret 支持 Base64 加密
  • Secret 分为 Opaque、kubernetes.io/Service Account、kubernetes.io/dockerconfigjson 三种类型,ConfigMap 不区分类型
  • Secret 文件存储在 tmpfs 文件系统中,Pod 删除后 Secret 文件也会对应被删除

3.2 默认令牌 Secret

Service Accounts 使用 API 证书自动创建并且绑定 Secret。

kubernetes 系统可以自动创建用于访问 API 证书的 Secret,并且可以自动绑定到 Pod 中使用这种类型的 Secret。可以根据需要禁用或覆盖重写这类 Secret,但是通常情况下如果考虑到安全性,更加推荐使用系统默认创建的 Secret。

在终端执行如下命令可以查看系统默认创建的 Secret:

$ kubectl get secrets
NAME                                             TYPE                                  DATA   AGE
default-token-sths6                              kubernetes.io/service-account-token   3      73d
deployment-controller-token-9qzdj                kubernetes.io/service-account-token   3      73d
disruption-controller-token-hbc8l                kubernetes.io/service-account-token   3      73d
endpoint-controller-token-qr2rf                  kubernetes.io/service-account-token   3      73d
expand-controller-token-mbmks                    kubernetes.io/service-account-token   3      73d
generic-garbage-collector-token-5drr7            kubernetes.io/service-account-token   3      73d
horizontal-pod-autoscaler-token-54xdg            kubernetes.io/service-account-token   3      73d
job-controller-token-4tgns                       kubernetes.io/service-account-token   3      73d
kube-proxy-token-9hc24                           kubernetes.io/service-account-token   3      73d
metrics-server-token-lj9th                       kubernetes.io/service-account-token   3      73d
namespace-controller-token-tng4h                 kubernetes.io/service-account-token   3      73d
nfs-provisioner-token-4wk59                      kubernetes.io/service-account-token   3      73d
node-controller-token-x8b8s                      kubernetes.io/service-account-token   3      73d
persistent-volume-binder-token-whx8d             kubernetes.io/service-account-token   3      73d
pod-garbage-collector-token-djjmp                kubernetes.io/service-account-token   3      73d

如果想要查看 Secrets 详细信息,可以执行命令 kubectl describe secrets

$ kubectl describe secrets default-token-sths6
Name:         default-token-sths6
Namespace:    kube-system
Labels:       <none>
Annotations:  kubernetes.io/service-account.name: default
              kubernetes.io/service-account.uid: 11d565d8-3a67-4f5e-973b-c9b46ca0524f

Type:  kubernetes.io/service-account-token

Data
====
token:      eyJhbGciOiJSUzI1NiIsImtpZCI6InhNbEpVRDZOUDRzUGlLdndDdk9qWGlYNnplMHMwazVMQVhIdmxaTHAzajQifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJkZWZhdWx0LXRva2VuLXN0aHM2Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImRlZmF1bHQiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiIxMWQ1NjVkOC0zYTY3LTRmNWUtOTczYi1jOWI0NmNhMDUyNGYiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06ZGVmYXVsdCJ9.XQ9_MEbfZroZeZPdxFrue8yAqz9L-Y7YSNC1tldf6iTALWHWjjtHgXVhCABhTUz-slykpN-BD8hCQAnmkxWyyUh6xOVEV4xAhbPA77D-o3R5uvsnGCrXID2Un17b7oWyMVKTmZdKE1OLz4Re5iCNLV5ElXqLFCfgNYZ7sHT9eIbT-YdsRJljJnjXLMHYjEdH6Oc1lSArfxm4sBB_HuXgbOql0DkVqj9cFBYSNJjoSYc9oSwkzdFTbKYiILcL2wMRyTLZvrV6rm2F_jnYPmtXFbXCYFkN72aEFAEx9OJPmWckY-iXu9BEytW_kA-QiZBeDTQorjQovfW2m4mLS3k3zw
ca.crt:     1025 bytes
namespace:  11 bytes

可以看到这个 Secret 包含 3 项配置信息,分别为:namespace、ca.crt、token,这是从 pod 内部安全访问 Kubernetes API 服务器的全部配置信息了。

新建 nginx-manual.yaml 文件,并向该文件中写入如下内容:

apiVersion: v1
kind: Pod
metadata:
  name: nginx-manual
spec:
  containers:
    - image: nginx:1.9.1
      name: nginx
      ports:
        - containerPort: 80
          protocol: TCP

执行创建:

$ kubectl create -f nginx-manual.yaml
pod/nginx-manual created

执行命令 kubectl describe pod nginx-manual 查看详细信息,可以发现:

# 这里显示了 default-token-k75dn Secret 被挂载到了容器中的 /var/run/secrets/kubernetes.io/serviceaccount 目录
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-k75dn (ro)

查看容器该目录下的文件名是否符合:

$ kubectl exec nginx-manual ls /var/run/secrets/kubernetes.io/serviceaccount
ca.crt
namespace
token

需要注意的是:当 Pod 被 API Server 创建时,API Server 不会校验该 Pod 引用的 Secret 是否存在。一旦这个 Pod 被调度,则 kubelet 将试着获取 Secret 的值。如果 Secret 不存在或暂时无法连接到 API Secret,则 kubelet 会按照一定的时间间隔定期重试获取该 Secret,并发送一个 Event 来解释 Pod 没有启动的原因,一旦 Secret 被 Pod 获取,则 kubelet 将创建并挂载包含 Secret 的 Volume,只有所有 Volume 都挂载成功,Pod 中的 Container 才会被启动。


3.3 使用 kubectl 创建 Secret

本节内容将会介绍 3 种方式创建 Secret,分别为:使用 kubectl 创建 Secret、使用 YAML 文件手动创建 Secret、以及 使用生成器创建 Secret。

使用 kubectl 创建 Secret

有时一些 Pods 需要进入数据库,我们在本地机器上定义 username.txtpassword.txt 文件存储 Pod 需要使用的用户名和密码。

$ echo -n 'admin' > username.txt
$ echo -n 'Az123456_' > password.txt

使用 kubectl create secret 命令以及参数 --from-file 指定使用这些文件调用 Api 服务器创建 Secret:

$ kubectl create secret generic db-user-pass --from-file=/root/learning/username.txt --from-file=/root/learning/password.txt
secret/db-user-pass created

查看刚刚创建的 Secret:

$ kubectl get secrets
NAME                  TYPE                                  DATA   AGE
db-user-pass          Opaque                                2      20s
# 使用 describe 默认不会展示 secrets 的内容
$ kubectl describe secrets db-user-pass
Name:         db-user-pass
Namespace:    user-test
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
password.txt:  9 bytes
username.txt:  5 bytes

3.4 使用 YAML 文件手动创建 Secret

可以使用文件创建 Secret 对象,文件可以为 json 或是 yaml 数据格式,定义 Secret 时分别有两种字段:data 和 stringData。data 字段存储被 Base64 编码以后的数据,而 stringData 字段的使用会更加随意一些,可以存储数据的纯文本值。

比如,使用 data 字段在 Secret 中存储两个字符串,使用如下命令将它们使用 Base64 编码:

$ echo -n 'admin' | base64
YWRtaW4=
$ echo -n 'Az123456_' | base64
QXoxMjM0NTZf

新建 secret.yaml 文件,并写入如下内容:

apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  username: YWRtaW4=
  password: QXoxMjM0NTZf

执行创建:

$ kubectl create -f secret.yaml
secret/mysecret created

如果想要在配置的时候更加明确配置信息,这个时候就需要使用到 stringData 字段了,使用这个字段可以将未被 Base64 编码的数据直接配置到 YAML 文件中,当创建或是更新 Secret 的时候、数据将自动被 Base64 加密并存储。

新建 secret-2.yaml 文件,并写入如下内容:

apiVersion: v1
kind: Secret
metadata:
  name: mysecret-2
type: Opaque
stringData:
  config.yaml: |-
    apiUrl: "https://my.api.com/api/v1"
    username: admin
    password: Az123456_
$ kubectl create -f secret-2.yaml
secret/mysecret-2 created

stringData 字段是只写的,使用 kubectl get -o yaml 获取 Secret 的 YAML 格式定义时,不会显示 stringData 字段,stringData 字段下面的所有条目会被 Base64 编码之后展示在 data 字段下:

$ kubectl get secret mysecret-2 -o yaml
apiVersion: v1
data:
  config.yaml: YXBpVXJsOiAiaHR0cHM6Ly9teS5hcGkuY29tL2FwaS92MSIKdXNlcm5hbWU6IGFkbWluCnBhc3N3b3JkOiBBejEyMzQ1Nl8g
kind: Secret
...

如果一个配置项在 data 字段和 stringData 字段中都被定义了,那么会使用来自 stringData 的值,比如新建 secret-3.yaml 文件,并写入如下内容:

apiVersion: v1
kind: Secret
metadata:
  name: mysecret-3
type: Opaque
data:
  username: YWRtaW4=
stringData:
  username: administrator

执行创建并且获取它的配置信息,如下所示:

apiVersion: v1
data:
  username: YWRtaW5pc3RyYXRvcg==
kind: Secret
...

其中,YWRtaW5pc3RyYXRvcg== 解码就为 administrator


3.5 使用生成器创建 Secret

kubectl 从 v1.14 版本开始支持使用 Kustomize 管理对象,具体的使用方法类似于 ConfigMap,生成器需要被明确定义在 kustomization.yaml 文件中。

执行如下命令创建一个 kustomization.yaml 文件,在其中使用 Secret 生成器字段 secretGenerator:

$ cat <<EOF >/root/learning/kustomization.yaml
secretGenerator:
- name: db-user-pass
  files:
  - username.txt
  - password.txt
EOF

执行创建:

$ kubectl apply -k .
secret/db-user-pass-k48fdchcmh created

# 生成的 secret 名称后面带有一个后缀,这样可以保证每次生成器修改之后都生成了新的 secret
$ kubectl get secrets
NAME                      TYPE                                  DATA   AGE
db-user-pass              Opaque                                2      20m
db-user-pass-k48fdchcmh   Opaque                                2      35s

也可以使用 key-value 键值对创建 Secret:

$ cat <<EOF >/root/learning/kustomization.yaml
secretGenerator:
- name: db-user-pass
  literals:
  - username=admin
  - password=Az123456_
EOF
$ kubectl apply -k .
secret/db-user-pass-9gkddh495h created

获取详细信息:

$ kubectl get secrets db-user-pass-9gkddh495h -o yaml
apiVersion: v1
data:
  password: QXoxMjM0NTZf
  username: YWRtaW4=
kind: Secret
...

$ echo 'YWRtaW4=' | base64 --decode
admin

对于一个已经存在的 Secret 可以使用命令 kubectl edit secrets xxx 更新其中的 data 字段。


3.6 挂载 Secret 到 Pod 中作为卷进行使用

在 Pod 的容器中,Secrets 可以被挂载成为数据卷或是引用为环境变量来使用。另外还可以在私有仓库 Docker 镜像拉取时配置进行使用。

挂载 Secret 到 Pod 中作为卷进行使用

通常将 Secret 作为挂载卷在 Pod 中使用的步骤如下:

  1. 创建一个 Secret 或是使用已经存在的 Secret。通常多个 Pods 会使用同一个 Secret。
  2. 修改 Pod YAML 文件定义,使用字段 .spec.volumes[] 挂载卷,卷的名称可以任意命名,在字段 .spec.volumes[].secret.secretName 中填写需要挂载的 Secret 对象的名称。
  3. 在每个需要 Secret 的容器中添加字段 .spec.containers[].volumeMounts[]。规定 .spec.containers[].volumeMounts[].readOnly = true 以及字段 .spec.containers[].volumeMounts[].mountPath 表示将 Secret 挂载到某个未使用过的目录下。
  4. 修改镜像或是命令行以便程序可以在对应的目录下找到需要的文件。Secret data 字段下的每个 key 都会被用作挂载目录下的文件名。

比如这个 YAML 文件定义了将 mysecret 挂载到容器中的 /etc/foo 目录下:

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
    - name: mypod
      image: nginx:1.9
      volumeMounts:
        - name: foo
          mountPath: "/etc/foo"
          readOnly: true
  volumes:
    - name: foo
      secret:
        secretName: mysecret

执行创建并进入到容器中查看:

$ kubectl exec -it mypod sh
# ls /etc/foo
password  username
# cat /etc/foo/username
admin# cat /etc/foo/password
Az123456_#

如果想要指定挂载的文件名可以使用 items 和 path 字段,将上面的定义修改为:

# 将 username secret 的值存储到 /etc/foo/my-group/my-username 文件中,同时 username secret 不会被使用到
......
  volumes:
  - name: foo
    secret:
      secretName: mysecret
      items:
      - key: username
        path: my-group/my-username

3.7 使用 Secret 作为环境变量

在 Pod 中使用 Secret 作为环境变量的步骤如下:

  1. 创建一个 Secret 或是使用已经存在的 Secret。通常多个 Pods 会使用同一个 Secret。
  2. 修改 Pod YAML 文件,在每个容器中添加环境变量引用需要的 Secret 的值,使用字段 env[].valueFrom.secretKeyRef
  3. 修改镜像或是命令行以便程序可以通过环境变量找到需要的值。

下面是一个 Pod YAML 文件从环境变量中使用 Secret:

apiVersion: v1
kind: Pod
metadata:
  name: secret-env-pod
spec:
  containers:
    - name: mycontainer
      image: nginx:1.9
      env:
        - name: SECRET_USERNAME
          valueFrom:
            secretKeyRef:
              name: mysecret
              key: username
        - name: SECRET_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysecret
              key: password
  restartPolicy: Never

执行创建并进入容器检查环境变量:

$ kubectl exec -it secret-env-pod bash
root@secret-env-pod:/# echo $SECRET_USERNAME
admin
root@secret-env-pod:/# echo $SECRET_PASSWORD
Az123456_

3.8 使用镜像拉取 Secret(ImagePullSecrets)

当需要从某个私有仓库拉取镜像时,可以使用 Secret 存储私有仓库的密码并借助 kubelet 传递密码,具体定义时通过指定 Pod 的字段 spec.ImagePullSecrets 来引用它。

这里有两个步骤:

  1. 创建包含 Docker 镜像仓库证书的 Secret
  2. 在 Pod 定义中使用字段 ImagePullSecrets 引用该 Secret

Docker Hub 上创建一个账号,使用该账号创建一个私有仓库。

使用如下命令创建用于 Docker 镜像仓库鉴权的 Secret:

# 这里的 xxxx 替换为你们自己的账号信息
$ kubectl create secret docker-registry mydockerhubsecret --docker-username=xxxx --docker-password=xxxx --docker-email=xxxx
secret/mydockerhubsecret created

查看详细信息:

$ kubectl get secret mydockerhubsecret -o yaml
apiVersion: v1
data:
  .dockerconfigjson: eyJhdXRocyI6eyJodHRwczovL2luZGV4LmRvY2tlci5pby92MS8iOnsidXNlcm5hbWUiOiJzYW55aXNoZW5nIiwicGFzc3dvcmQiOiI4MjYxMDMyMCxxIiwiZW1haWwiOiJzaXRlc0B6aGFuamllLm1lIiwiYXV0aCI6ImMyRnVlV2x6YUdWdVp6bzRNall4TURNeU1DeHgifX19
kind: Secret
...

可以看到 mydockerhubsecret Secret 有一个隐藏的 .dockerconfigjson 文件,这个文件就是用于帮助验证的。

然后在创建 Pod 的时候引用这个 mydockerhubsecret:

apiVersion: v1
kind: Pod
metadata:
  name: private-pod
spec:
  imagePullSecrets:
    - name: mydockerhubsecret
  containers:
    - image: username/private:tag # 这里根据实际情况添加私有仓库的镜像名
      name: main
  restartPolicy: Never
0

评论区