什么是ServiceAccount ServiceAccount是Kubernetes中容器用来访问default空间下kubernetes服务的认证机制。我们可以通过kubectl get svc来查看kubernetes服务:1
2
3
root@fankang:/home/fankang# kubectl get svc kubernetes
NAME         CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   10.100.0.1   <none>        443/TCP   189d
访问kubernetes等同于kube-apiserver的认证端口。当把ServiceAcount的信息传递给容器后,容器中的进程便可以使用ServiceAccount包含的Secret访问kubernetes服务,即10.100.0.1地址。
那么哪些服务需要访问kubernetes服务呢,比如heapster,ingress-controller等,这些都需要从kube-apiserver获取系统资源。
生成ServiceAccount  先来看下如何搭建带ServiceAccount的Kubernetes环境。我的实验环境是虚拟机单机环境,为了方便测试,所有进程都是直接从二进制文件拉起,所以读者需要依据自己的环境修改启动参数。关于key和config机制,请参考另外的相关文章。1
2
3
4
5
6
7
8
9
10
11
12
13
14
(dockerd -H 0.0.0.0:4243 -H unix:///var/run/docker.sock &>> /var/log/docker.log &)
(etcd --data-dir=/home/fankang/data/etcd150/ --listen-client-urls http://0.0.0.0:4001 --advertise-client-urls http://0.0.0.0:4001 &>> /var/log/etcd.log &)
(启动etcd后稍后启动kubenetes进程)
(kube-apiserver --logtostderr=true --v=0 --etcd-servers=http://localhost:4001 --insecure-bind-address=0.0.0.0 --allow-privileged=false --service-cluster-ip-range=10.100.0.0/16 --admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,ResourceQuota,ServiceAccount --client-ca-file=/etc/kubernetes/security/serverkey/ca.crt --tls-private-key-file=/etc/kubernetes/security/serverkey/server.key --tls-cert-file=/etc/kubernetes/security/serverkey/server.crt &>> /var/log/kube-apiserver.log &)
(kube-controller-manager --logtostderr=true --v=0 --kubeconfig=/root/.kube/config --service_account_private_key_file=/etc/kubernetes/security/serverkey/server.key --root-ca-file=/etc/kubernetes/security/serverkey/ca.crt &>> /var/log/kube-controller-manager.log &)
(kube-scheduler --logtostderr=true --v=0 --kubeconfig=/root/.kube/config &>> /var/log/kube-scheduler.log &)
(kube-proxy --logtostderr=true --v=0 --kubeconfig=/root/.kube/config &>> /var/log/kube-proxy.log &)
(kubelet --logtostderr=true --v=0 --address=0.0.0.0 --allow-privileged=false --pod-infra-container-image=pause:0.8.0 --cpu-cfs-quota=true --kubeconfig=/root/.kube/config --require-kubeconfig=True &>> /var/log/kubelet.log &)
下面我们以default空间为例来查看ServiceAccount。
进程启动完成后,可以通过kubectl get secret查看在default空间(其他空间下类似)下是否有default-token:1
2
3
root@fankang:/home/fankang# kubectl get secret
NAME                  TYPE                                  DATA      AGE
default-token-zg893   kubernetes.io/service-account-token   3         8d
default-token中包含有ca.crt, namespace, token三个字段信息,且都是base64编码。1
2
3
4
5
6
7
8
9
10
11
12
13
14
root@fankang:/home/fankang# kubectl get secret default-token-zg893 -o yaml
apiVersion: v1
data:
  ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUQ5VENDQXQyZ0F3SUJBZ0lKQUpQbWJ1cm4xNXAzTUEwR0NTcUdTSWIzRFFFQkN3VUFNSUdRTVFzd0NRWUQKVlFRR0V3SkRUakVSTUE4R0ExVUVDQXdJV21obGFtbGhibWN4RVRBUEJnTlZCQWNNQ0VoaGJtZDZhRzkxTVJBdwpEZ1lEVlFRS0RBZG9hV3RrWVhSaE1SQXdEZ1lEVlFRTERBZG9hV3RrWVhSaE1STXdFUVlEVlFRRERBcHJkV0psCmNtNWxkR1Z6TVNJd0lBWUpLb1pJaHZjTkFRa0JGaE5tWVc1cllXNW5RR2hwYTJSaGRHRXVZMjl0TUI0WERURTMKTURZeU9URXlNamt5TUZvWERUSTNNRFl5TnpFeU1qa3lNRm93Z1pBeEN6QUpCZ05WQkFZVEFrTk9NUkV3RHdZRApWUVFJREFoYWFHVnFhV0Z1WnpFUk1BOEdBMVVFQnd3SVNHRnVaM3BvYjNVeEVEQU9CZ05WQkFvTUIyaHBhMlJoCmRHRXhFREFPQmdOVkJBc01CMmhwYTJSaGRHRXhFekFSQmdOVkJBTU1DbXQxWW1WeWJtVjBaWE14SWpBZ0Jna3EKaGtpRzl3MEJDUUVXRTJaaGJtdGhibWRBYUdsclpHRjBZUzVqYjIwd2dnRWlNQTBHQ1NxR1NJYjNEUUVCQVFVQQpBNElCRHdBd2dnRUtBb0lCQVFDNzFrQmxaelp6Q1RhdDVIcm1FaUR5bTdLS1BoRm5nRkx5YzZmSmI0bTVVU0g0CkJWaitiTmYrYzkyd3hRZnNHTy9XNTlXaXV0T1N3YXgvSVZuWlBBRmd4NnEvNGdnR0l0VDdwVFFUbDR2SWpkc1IKMW1ZZmdqd0h5dThIOWxRYlRJOElFT3poMUozUzAvTVUwWUozdTFLOW9YT3JDa2Zha3NRWXVtVVdSbWVGTCtpTgp6azM5UGRPenE4SnFKajNqOWgxK3hIaEQzZC9MYkRqY0xDMWhjbHM4VldCWk9CR1QrVlR0elIwTHZzWEhKOVlhCkJ6YTlKYVJIVEpTeEU2NE1JNHRDR3B2TytOZjZOdjZnTUdkN2pJNnB0TDhabS8yYWs2R2tRRnRUVnNnam5lSFoKdXpOY0hkTnFTVEIycTZDNEZVWWZybzFDUkhaWUVrZWFWVSswSUNSMUFnTUJBQUdqVURCT01CMEdBMVVkRGdRVwpCQlNEMHBjeUMxNkpCSTA4TTNwWlI2WjlZMDNHVFRBZkJnTlZIU01FR0RBV2dCU0QwcGN5QzE2SkJJMDhNM3BaClI2WjlZMDNHVFRBTUJnTlZIUk1FQlRBREFRSC9NQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUFZeXFtRm92ZDkKby9Ka1dzSlY5VXgzdWc4c0VWSHNSNXJTdXpSakJuWUQzakw1MkFFTDdKTjB0YTdwT0h3N3BaQWgyZXpobTJKSwprYnNGbjRpbzRiZ21TN2FLdHgxeGRVbnIvbXovMUhBbVFHS1dMQnFSMDdLUm9zY0JvdkpwMEpyYjlrQVk3Tm9SCnhONGRTNzBDM0ZvNlZHSTBrL3lwL1hnZkZnZU80R24yTnJiT0dDODRiNjBhYS9JWTM2T09uNFpUdFJSS0pZOUMKMDQwNyt1SmV6TThvakdkakRaMGpIN3hoMDJ3dFBWZTlnRk4yblpEVW5YYUF1SGtvbVJmWGFKS0pFbDNhcjZoRgplYjlHLzZVMURBTlkvK3JTRmZ5dFU1WCt6S3RqbjRudGRmMGRJckdtZ2s5d3plUFg3RWZZYWdvbW1MVUd0S1B4CmY4aTQ2VWJ6YUhGeAotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
  namespace: ZGVmYXVsdA==
  token: ZXlKaGJHY2lPaUpTVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SnBjM01pT2lKcmRXSmxjbTVsZEdWekwzTmxjblpwWTJWaFkyTnZkVzUwSWl3aWEzVmlaWEp1WlhSbGN5NXBieTl6WlhKMmFXTmxZV05qYjNWdWRDOXVZVzFsYzNCaFkyVWlPaUprWldaaGRXeDBJaXdpYTNWaVpYSnVaWFJsY3k1cGJ5OXpaWEoyYVdObFlXTmpiM1Z1ZEM5elpXTnlaWFF1Ym1GdFpTSTZJbVJsWm1GMWJIUXRkRzlyWlc0dGVtYzRPVE1pTENKcmRXSmxjbTVsZEdWekxtbHZMM05sY25acFkyVmhZMk52ZFc1MEwzTmxjblpwWTJVdFlXTmpiM1Z1ZEM1dVlXMWxJam9pWkdWbVlYVnNkQ0lzSW10MVltVnlibVYwWlhNdWFXOHZjMlZ5ZG1salpXRmpZMjkxYm5RdmMyVnlkbWxqWlMxaFkyTnZkVzUwTG5WcFpDSTZJbVptWW1OaE1qazVMVFZqWXprdE1URmxOeTA1TnpZd0xUQTRNREF5TnpjeFpUTTVNeUlzSW5OMVlpSTZJbk41YzNSbGJUcHpaWEoyYVdObFlXTmpiM1Z1ZERwa1pXWmhkV3gwT21SbFptRjFiSFFpZlEuRlN1TF9KMzQzdVl3eUJtSVVjMG02cXZKc2NITUM4YU1MNFJ1eVV4ZmtRcmk1amVlZXhuQzdCT0dqWnJmNURzWWFYa051ajZWb0d6RHk1M0FFdkIxdm5Hb0lhQkNLZXdFY1JyWW9nWmcxTk9pLUNqelFtYS02dE9ySkU2STZkUnJ4Q3dJb2ZsaWlRaTFRdDEwTlRYdVRwaG9IYnZ0X1JXLTBDeV9sdWg1amJQLTZ3RURUTzNEc24xSldfdGZSSktaejEzLWtTQ2RDVV9VS0gzektiaERvLTdTR1R5ZnJOTktDbldGSmd1R3VPWFFJMW15VHVxY0ZDSy1pQjlKNTdCeS1rMzQ1MmtrSTlsVlNRQmZIY3JPbXJaX1JvSWx0RXZxMnBudUFNcExtbWM4OG95RkwzLTFKdXBaV1FMRzQxazJFb0VHVmhYS1ZNOU11bXlubzJweTVn
kind: Secret
metadata:
  annotations:
    kubernetes.io/service-account.name: default
    kubernetes.io/service-account.uid: ffbca299-5cc9-11e7-9760-08002771e393
  creationTimestamp: 2017-06-29T12:55:57Z
  name: default-token-zg893
  namespace: default
其中:
ca.crt可以通过cat ca.crt | base64生成;  
Namespace可以通过echo -n "kube-system" | base64生成;  
Token随机生成。 
 
然后查看default空间下是否有default ServiceAccount:1
2
3
root@fankang:/home/fankang# kubectl get sa
NAME      SECRETS   AGE
default   1         8d
此时的default ServiceAccount包含1个Secret,Secret名字就是上面提到的default-token:1
2
3
4
5
6
7
8
9
10
11
12
root@fankang:/home/fankang# kubectl get sa default -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  creationTimestamp: 2017-06-29T12:53:50Z
  name: default
  namespace: default
  resourceVersion: "1243200"
  selfLink: /api/v1/namespaces/default/serviceaccounts/default
  uid: ffbca299-5cc9-11e7-9760-08002771e393
secrets:
- name: default-token-zg893
如果default ServiceAccount中不包含Secret,那么很可能是default-token不存在,请检查kube-controller-manager的–service_accoujnt_private_key_file和–root-ca-file两个参数是否正确,并重新启动kube-controller-manager。
ServiceAccount使用 因为我们在kube-apiserver中的–admision-control中已经开启了ServiceAccount,那么我们就可以直接起容器来使用ServiceAccont。
我们来启动一个ubuntu-ssh的Deployment。Deployment代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
apiVersion: extensions/v1beta1
kind: Deployment
metadata: 
  name: ubuntu-ssh
  namespace: default
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: ubuntu-ssh
    spec:
      containers:
      - name: ubuntu-ssh
        image: ubuntu-ssh:v1
        env:
        - name: ROOT_PASSWORD
          value: "123456"
        ports:
        - containerPort: 22
          name: ssh
        resources:
          limits:
            cpu: 100m
            memory: 100Mi
          requests:
            cpu: 100m
            memory: 100Mi
待Pod启动完成后,可以看到容器中已经把default-token挂载到容器的/var/run/secrets/kubernetes.io/servicesaccount目录:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
root@fankang:/home/fankang# kubectl describe pods ubuntu-ssh-589933015-2lhgb
Name:       ubuntu-ssh-589933015-2lhgb
Namespace:  default
Node:       fankang/10.0.2.15
Start Time: Fri, 30 Jun 2017 14:32:40 +0800
Labels:     app=ubuntu-ssh
        pod-template-hash=589933015
Status:     Running
IP:     172.17.0.7
Controllers:    ReplicaSet/ubuntu-ssh-589933015
Containers:
  ubuntu-ssh:
    Container ID:   docker://5eb46b23c2d2237c98c6d6c0b47bdf37db9ede2ba2170a62aae8b3ecdc178574
    Image:      ubuntu-ssh:v1
    Image ID:       docker://sha256:27312dad4272a61739c317b90bfab5bc129e38696df5c606b1041199caf03ea4
    Port:       22/TCP
    Limits:
      cpu:  100m
      memory:   100Mi
    Requests:
      cpu:      100m
      memory:       100Mi
    State:      Running
      Started:      Sat, 08 Jul 2017 18:35:40 +0800
    Last State:     Terminated
      Reason:       Completed
      Exit Code:    0
      Started:      Fri, 07 Jul 2017 14:13:58 +0800
      Finished:     Fri, 07 Jul 2017 15:33:17 +0800
    Ready:      True
    Restart Count:  2
    Volume Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token (ro)
    Environment Variables:
      ROOT_PASSWORD:    123456
Conditions:
  Type      Status
  Initialized   True 
  Ready     True 
  PodScheduled  True 
Volumes:
  default-token:
    Type:   Secret (a volume populated by a Secret)
    SecretName: default-token-zg893
QoS Class:  Guaranteed
Tolerations:    <none>
Events:
  FirstSeen LastSeen    Count   From            SubObjectPath           Type        Reason          Message
  --------- --------    -----   ----            -------------           --------    ------          -------
  36m       36m     2   {kubelet fankang}                   Warning     MissingClusterDNS   kubelet does not have ClusterDNS IP configured and cannot create Pod using "ClusterFirst" policy. Falling back to DNSDefault policy.
  36m       36m     1   {kubelet fankang}   spec.containers{ubuntu-ssh} Normal      Pulled          Container image "ubuntu-ssh:v1" already present on machine
  36m       36m     1   {kubelet fankang}   spec.containers{ubuntu-ssh} Normal      Created         Created container with docker id 5eb46b23c2d2; Security:[seccomp=unconfined]
  36m       36m     1   {kubelet fankang}   spec.containers{ubuntu-ssh} Normal      Started         Started container with docker id 5eb46b23c2d2
在容器/var/run/secrets/kubernetes.io/servicesaccount目录下有ca.crt, namespace, token三个文件,这和default-token中的内容是对应的。然后到/var/run/secrets/kubernetes.io/serviceaccount目录下,执行下面语句访问kubernetes服务。1
curl -H "Authorization: Bearer `cat token`" --cacert ca.crt -XGET https://10.100.0.1:443/api/v1/namespaces/default/pods -v
自挂载使用ServiceAccount 上节介绍了kube-apiserver开启ServiceAccount admission-controller情况下如何使用ServiceAccount。在该情况下,所有创建的Pod都会使用ServiceAccount,从而拥有访问kubernetes服务的能力。这当然不是我们希望看到的,我们希望部分容器可以访问kubernetes服务。
我们可以直接通过挂载ServiceAccount对应的secret来使用ServiceAccount。如下所示:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
apiVersion: extensions/v1beta1
kind: Deployment
metadata: 
  name: ubuntu-ssh
  namespace: default
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: ubuntu-ssh
    spec:
      containers:
      - name: ubuntu-ssh
        image: ubuntu-ssh:v1
        env:
        - name: ROOT_PASSWORD
          value: "123456"
        ports:
        - containerPort: 22
          name: ssh
        resources:
          limits:
            cpu: 100m
            memory: 100Mi
          requests:
            cpu: 100m
            memory: 100Mi
        volumeMounts:
        - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
          name: default-token
          readOnly: true
      volumes:
      - name: default-token
        secret:
          defaultMode: 420
          secretName: default-token-zg893
使用自定义ServiceAccount 一般来说,只要创建完ServiceAccount,kube-controller-manager会自动创建对应的secret,刚创建的ServiceAccount就有访问kubernetes的服务的权限。创建ServiceAccount的YAML文件如下:1
2
3
4
5
apiVersion: v1
kind: ServiceAccount
metadata:
  name: test-sa
  namespace: default