BDOS 部署 Kubernetes 最佳实践

by LINKTIME CLOUD 2019-08-07

BDOS 部署 Kubernetes 最佳实践

需要的集群环境:已有BDOS DC/OS集群
BDOS版本号:v3.0
BDOS上面部署Kubernetes集群其架构图较简单,如下所示:

4bc49397bd2b5e8e924b2367ba009138

BDOS Kubernetes的安装部署

我们这里主要是通过自己BDOS 本地universe来进行安装和部署,这里需要进到DC/OS的界面,点击”Catalog”菜单,显示结果如下所示:

0cb631a7abc9cabc01ed113862839468

然后选中kubernetes,然后选择”Review Run”菜单,显示结果如下所示:

3818df48157a68dd3a736601776ad8b1

默认集成的Kubernetes集群是只有一个Node节点,这里可以根据实际集群资源情况来选择相应的节点数,如下所示:

f335d753976b5d3e7e4480414c1d5c00

由于这里是在Stage集群上测试,所以这里填写的是2,其它配置都选择默认即可,最后点击”Review&Run”菜单。

如果一切顺利和正常,最终的效果应该如下所示:

49ed57f513651d5548227ce69427e43c

DC/OS Kubernetes的集群安装较为简单方便,到这里基本上就是成功安装了。

那么如何判断在一个新的DC/OS集群中到底是用几个kube node呢,这里主要是根据DC/OS的具体资源来判断,这里可以参考官方的部署文档,根据当前集群的实际资源占用情况来决定到底用几个node,表格如下所示:

每个集群的实例 每个CPU的实例 每个实例的Mem(MB) 每个实例的磁盘空间(MB)
Package scheduler 1 1 1024
etcd 1 0.5 1024
kube-apiserver 1 0.5 1024
kube-scheduler 1 0.5 512
kube-controller-manager 1 0.5 512
kube-proxy 1 0.1 512
kubelet 1 3 3072

据统计,单node节点需占用6.7CPU+7.7GB MEM+14.8G DiSK,2个node节点需占用10CPU+11.3GBMEM+25GB DISK资源,大家可以根据自己使用BDOS集群实际硬件环境来考虑使用几个node节点

部署TLS HTTPS证书来实施kubectl操作

Kubernetes集群有好几种认证方式,这里采用HTTPS证书认证,是基于CA根证书签名的双向数字证书认证方式,是最严格的认证

如果大家想用kubectl操作Kubernetews集群,这里也要区分为三种情况:

  • Kubernetes集群里
  • DC/OS集群里或Bootstrap机器上面
  • 集群之外的任意一台机器上面

假设现在在用户集群的Bootstrap机器上。
提前通过名为kube-apiserver-0-instance的UCR的Sandbox里面,下载下面config里面需要的相关证书文件,这步动作需要先用手动操作执行,主要涉及有以下文件:

  • client-ca-file.pem
  • kube-apiserver-crt.pem
  • kube-api-key.pem

从apiserver UCR中下载证书的实际操作如下:

  1. 直接通过wgt命令来下载kubectl命令行工具下载到当前目录,命令如下所示:
wget http://http://artifacts.linktime.cloud:8080/downloads/kubectl
  1. 使⽤用DCOS CLI查询apiserver的TaskId:
dcos task | grep apiserver

执行结果显示如下:

kube-apiserver-0-instance 192.168.5.252 root R kubernetes__kube- apiserver-0-instance__1e8a01e2-c427-4e0a-a50c-7183b703858c e32c41df-122c-4a06-8f14- d254cae6a7ce-S9 --- ---
  1. 使⽤DCOS CLI远程在UCR中执⾏ 行指令 并重定向到本地⽂文件,命令如下所示:
for c in client-ca-file.pem kube-apiserver-crt.pem kube-apiserver-key.pem; do dcos task exec -it kubernetes__kube-apiserver-0-instance__1e8a01e2-c427-4e0a-a50c-7183b703858c cat $c > ./$c; done

可以用tree命令来查看下,命令显示结果如下所示:

├── config
├── kube-apiserver-crt.pem
├── kube-apiserver-crt.srl
├── kube-apiserver-key.pem
└── kubectl

然后定义下KUBECONFIG环境变量,命令如下所示:
export KUBECONFIG=$PWD/config
然后执行下最简单的kubectl get node,看有无显示。
这个时候是有正常显示的:

NAME                                   STATUS    ROLES     AGE       VERSION
kube-node-0-kubelet.kubernetes.mesos   Ready     <none>    6d        v1.10.8
kube-node-1-kubelet.kubernetes.mesos   Ready     <none>    4d        v1.10.8

较复杂的一种情况下,如果是使用自己的MAC来跟DC/OS Kubernetes集群的api-server来进行交互呢?
其实此时只需替换下server地址即可,如下:

server: https://apiserver:6443

然后修改/etc/hosts文件,确保里面有如下内容
apiserver 192.168.4.92

这里的apiserver具体要根据当前实际安装情况待定了,因为每一次DC/OS Kubernetes集群安装,apiserver的具体位置都会发生变化

这个时候也是能正常的使用kubectl来进行操作了。

kubectl操作Kubernetes集群各种资源

这里用kubectl自己创建需要的pod,nginx.yaml文件如下所示:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 2 # tells deployment to run 2 pods matching the template
  template: # create pods using pod definition in this template
    metadata:
      # unlike pod-nginx.yaml, the name is not included in the meta data as a unique name is
      # generated from the deployment name
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80

创建pod的命令如下所示:

kubectl create -f nginx.yaml

查看deployment的命令如下所示(附上结果):

kubectl get deployment
NAME               DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   2         2         2            2           16h

接下来可以用kubectl describe deployment来了解更多详细的信息,如下所示:

kubectl describe deployment nginx-deployment

然后可以用kubectl describe replicaset查看详细信息,命令如下所示:

kubectl get replicaset
kubectl describe replicaset

命令显示结果如下所示:

1334c40c192576e1edba155c650a06e3

然后可以用以下命令来查看pod,如下所示:

kubectl get pod -o wide

命令显示结果如下所示:

NAME                                READY     STATUS    RESTARTS   AGE       IP         NODE
nginx-deployment-75675f5897-f8lsn   1/1       Running   0          18h       9.0.7.6    kube-node-0-kubelet.kubernetes.mesos
nginx-deployment-75675f5897-w9vsp   1/1       Running   0          18h       9.0.13.3   kube-node-1-kubelet.kubernetes.mesos

这里怎么在线增加或减少pod的副本数呢?这里只需要更改replicas后面的数字为3就行,如下所示:

replicas: 3

然后再执行 kubectl apply -f nginx.yaml文件,然后显示pod结果如下所示:

NAME                                READY     STATUS    RESTARTS   AGE       IP         NODE
nginx-deployment-75675f5897-ll6bz   1/1       Running   1          22h       9.0.7.7    kube-node-0-kubelet.kubernetes.mesos
nginx-deployment-75675f5897-mcxcv   1/1       Running   0          22h       9.0.13.4   kube-node-1-kubelet.kubernetes.mesos
nginx-deployment-75675f5897-mjrnx   1/1       Running   0          1m        9.0.13.7   kube-node-1-kubelet.kubernetes.mesos

大家应该能理解,每个pod都有自己的IP地址。当Controller用新的pod替代发生故障的pod时,新pod会分配到新的IP地址,这样就产生了一个问题:
如果一组pod对外提供服务,例如:Nginx,它们的IP很有可能发生变化,那么客户端如何找到并访问这个服务呢?
Kubernetes给出的解决方案是Service。

好,这建立nginx-svc.yaml文件,文件内容如下所示:

apiVersion: v1
kind: Service
metadata:
 name: nginx-svc
spec:
 selector:
  app: nginx 
 ports:
 - protocol: TCP
   port: 8080
   targetPort: 80

启动此service,命令如下所示:

kubectl apply -f nginx-svc.yaml

这里可以看到,除了nginx-svc以外,这里还有kubernetes,Cluster内部通过这个service访问Kubernetes API Server。
然后再可以通过命令来查看详细

kubectl describe service

然后就可以查看service了,命令显示结果如下所示:

NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
kubernetes   ClusterIP   10.100.0.1    <none>        443/TCP    3d
nginx-svc    ClusterIP   10.100.6.69   <none>        8080/TCP   2h

这里可以启动一个busybox容器来进行测试工作,命令如下所示:

kubectl run busybox --rm -ti --image=busybox /bin/sh

然后执行以下命令:

wget 10.100.6.69:8080

此pod的网络调试工具挺多的,但是没有curl,所以这里用wget

可以用describe来查看nginx-svc服务的明细,显示结果如下所示:

Name:              nginx-svc
Namespace:         default
Labels:            <none>
Annotations:       <none>
Selector:          app=nginx
Type:              ClusterIP
IP:                10.100.6.69
Port:              <unset>  8080/TCP
TargetPort:        80/TCP
Endpoints:         9.0.13.4:80,9.0.7.7:80
Session Affinity:  None
Events:            <none>

注:此时的ClusterIP是虚拟IP,一般来说,只能被Cluster内的pod访问到
大家注意下面的iptables防火墙规则,如下所示:

-A KUBE-SERVICES -d 10.100.6.69/32 -p tcp -m comment --comment "default/nginx-svc: cluster IP" -m tcp --dport 8080 -j KUBE-SVC-R2VK7O5AFVLRAXSH

这个时候怎么能让k8s集群外的应用访问此nginx应用呢?用此ClusterIP显示不合适的,这个时候一般可以用NodePort或Ingress的方式,这里用30080来固定,其配置文件node-nginx.yaml内容如下所示:

apiVersion: v1
kind: Service
metadata:
 name: node-nginx
spec:
 type: NodePort
 selector:
  app: nginx 
 ports:
 - protocol: TCP
   nodePort: 30080
   port: 8080
   targetPort: 80

这里注意的点是:

nodePort是真实的node物理服务器监听的端口
port是ClusterIP上监听的端口
targetPort是Pod上监听的端口

这个时候get下service,会发现其中还是有区别的,命令结果显示如下所示:

NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
kubernetes   ClusterIP   10.100.0.1      <none>        443/TCP          3d
nginx-svc    ClusterIP   10.100.6.69     <none>        8080/TCP         3h
node-nginx   NodePort    10.100.157.56   <none>        8080:30080/TCP   1m

node-ningx的的Type类型现在不是ClusterIP,而变成了NodePort了。

NAME                                   STATUS    ROLES     AGE       VERSION
kube-node-0-kubelet.kubernetes.mesos   Ready     <none>    3d        v1.10.8
kube-node-1-kubelet.kubernetes.mesos   Ready     <none>    1d        v1.10.

这个时候在DC/OS集群中ping分别ping下node,如下所示:

kube-node-0-kubelet.kubernetes.mesos 192.168.5.252
kube-node-1-kubelet.kubernetes.mesos 192.168.6.34

好了,最后就可以用curl 192.168.5.252:30080和192.168.6.34:30080来分别访问Nginx应用了。

如果要重现效果,此时可以删除这些pod及service资源,可以直接用下面的命令来操作,如下所示:

kubectl delete -f nginx.yaml

curl命令采取HTTPS证书方式来访问kube-apiserver

API的具体操作及明细我们可以参考官方文档,我们用curl命令也是能对apiserver进行复杂的GET、POST及DELETE等操作的,这里只列举几个简单的说明,如下所示:
证书相关文件我放在本地的/tmp/andrew/目录了,本地的/etc/hosts文件已经增添了apiserver主机地址,如下所示:

192.168.4.92  apiserver

获取所有namespace

命令如下所示:

curl -k --cacert /tmp/andrew/client-ca-file.pe --key /tmp/andrew/kube-apiserver-key.pem --cert /tmp/andrew/kube-apiserver-crt.pem -X GET https://apiserver:6443/api/v1/namespaces

获取所有的node

命令如下所示:

curl -k --cacert /tmp/andrew/client-ca-file.pe --key /tmp/andrew/kube-apiserver-key.pem --cert /tmp/andrew/kube-apiserver-crt.pem -X GET https://apiserver:6443/api/v1/nodes

获取所有的pod

命令如下所示:

curl -k --cacert /tmp/andrew/client-ca-file.pe --key /tmp/andrew/kube-apiserver-key.pem --cert /tmp/andrew/kube-apiserver-crt.pem -X GET https://apiserver:6443/api/v1/pods

命令显示结果部分如下所示:

  "items": [
    {
      "metadata": {
        "name": "nginx-deployment-75675f5897-ll6bz",
        "generateName": "nginx-deployment-75675f5897-",
        "namespace": "default",
        "selfLink": "/api/v1/namespaces/default/pods/nginx-deployment-75675f5897-ll6bz",
        "uid": "c529b4e8-a2c3-11e9-bde3-00163e00273c",
        "resourceVersion": "539184",
        "creationTimestamp": "2019-07-10T03:35:32Z",
        "labels": {
          "app": "nginx",
          "pod-template-hash": "3123191453"
        },
        "ownerReferences": [
          {
            "apiVersion": "extensions/v1beta1",
            "kind": "ReplicaSet",
            "name": "nginx-deployment-75675f5897",
            "uid": "c5261659-a2c3-11e9-bde3-00163e00273c",
100 47836    0 47836    0     0   218k      0 --:--:-- --:--:-- --:--:--  218k
            "controller": true,
            "blockOwnerDeletion": true
          }
        ]
      },
      "spec": {
        "volumes": [
          {
            "name": "default-token-hnfjz",
            "secret": {
              "secretName": "default-token-hnfjz",
              "defaultMode": 420
            }
          }
        ],
        "containers": [
          {
            "name": "nginx",
            "image": "nginx:1.7.9",
            "ports": [
              {
                "containerPort": 80,
                "protocol": "TCP"
              }
            ],
            "resources": {

            },
            "volumeMounts": [
              {
                "name": "default-token-hnfjz",
                "readOnly": true,
                "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount"
              }
            ],
            "terminationMessagePath": "/dev/termination-log",
            "terminationMessagePolicy": "File",
            "imagePullPolicy": "IfNotPresent"
          }
        ],
        "restartPolicy": "Always",
        "terminationGracePeriodSeconds": 30,
        "dnsPolicy": "ClusterFirst",
        "serviceAccountName": "default",
        "serviceAccount": "default",
        "nodeName": "kube-node-0-kubelet.kubernetes.mesos",
        "securityContext": {

        },
        "schedulerName": "default-scheduler",
        "tolerations": [
          {
            "key": "node.kubernetes.io/not-ready",
            "operator": "Exists",
            "effect": "NoExecute",
            "tolerationSeconds": 300
          },
          {
            "key": "node.kubernetes.io/unreachable",
            "operator": "Exists",
            "effect": "NoExecute",
            "tolerationSeconds": 300
          }
        ]
      },
      "status": {
        "phase": "Running",
        "conditions": [
          {
            "type": "Initialized",
            "status": "True",
            "lastProbeTime": null,
            "lastTransitionTime": "2019-07-10T03:35:32Z"
          },
          {
            "type": "Ready",
            "status": "True",
            "lastProbeTime": null,
            "lastTransitionTime": "2019-07-10T09:42:33Z"
          },
          {
            "type": "PodScheduled",
            "status": "True",
            "lastProbeTime": null,
            "lastTransitionTime": "2019-07-10T03:35:32Z"
          }
        ],
        "hostIP": "192.168.5.251",
        "podIP": "9.0.7.7",
        "startTime": "2019-07-10T03:35:32Z",
        "containerStatuses": [
          {
            "name": "nginx",
            "state": {
              "running": {
                "startedAt": "2019-07-10T09:42:32Z"
              }
            },
            "lastState": {
              "terminated": {
                "exitCode": 137,
                "reason": "Error",
                "startedAt": "2019-07-10T03:35:33Z",
                "finishedAt": "2019-07-10T09:42:26Z",
                "containerID": "docker://7c682f2db91ce88d2aaa21fe7a739952c747df0a8d9631d43e928a1116f62951"
              }
            },
            "ready": true,
            "restartCount": 1,
            "image": "nginx:1.7.9",
            "imageID": "docker-pullable://nginx@sha256:e3456c851a152494c3e4ff5fcc26f240206abac0c9d794affb40e0714846c451",
            "containerID": "docker://85d12f08d54d6b69b2994c4f15274b4db2e1523d16b768ccfabc496f26eba27e"
          }
        ],
        "qosClass": "BestEffort"
      }
    },
    {
      "metadata": {
        "name": "nginx-deployment-75675f5897-mcxcv",
        "generateName": "nginx-deployment-75675f5897-",
        "namespace": "default",
        "selfLink": "/api/v1/namespaces/default/pods/nginx-deployment-75675f5897-mcxcv",
        "uid": "c5293be8-a2c3-11e9-bde3-00163e00273c",
        "resourceVersion": "510425",
        "creationTimestamp": "2019-07-10T03:35:32Z",
        "labels": {
          "app": "nginx",
          "pod-template-hash": "3123191453"
        },
        "ownerReferences": [
          {
            "apiVersion": "extensions/v1beta1",
            "kind": "ReplicaSet",
            "name": "nginx-deployment-75675f5897",
            "uid": "c5261659-a2c3-11e9-bde3-00163e00273c",
            "controller": true,
            "blockOwnerDeletion": true
          }
        ]
      },
      "spec": {
        "volumes": [
          {
            "name": "default-token-hnfjz",
            "secret": {
              "secretName": "default-token-hnfjz",
              "defaultMode": 420
            }
          }
        ],
        "containers": [
          {
            "name": "nginx",
            "image": "nginx:1.7.9",
            "ports": [
              {
                "containerPort": 80,
                "protocol": "TCP"

建立新的pod

这里我们先建议名为nginx-new.json的文件,文件内容如下所示:

{
    "apiVersion": "v1",
    "kind": "Pod",
    "metadata": {
        "name": "nginx1"
    },
    "spec": {
        "containers": [
            {
                "name": "nginx",
                "image": "nginx:1.7.9",
                "ports": [
                    {
                        "containerPort": 80
                    }
                ]
            }
        ]
    }
}

然后我们用curl命令来建立新的pod,命令如下所示:

curl -k --cacert /tmp/andrew/client-ca-file.pem --key /tmp/andrew/kube-apiserver-key.pem --cert /tmp/andrew/kube-apiserver-crt.pem -X POST -H "Content-Type: application/json" https://apiserver:6443/api/v1/namespace/default/pods  -d@nginx-new.json

这里只是列举了些简单的kubectl操作及curl调用API操作用法,实际上大家可以在这个Kubernetes集群上面做更多复杂的操作:比如pod的ReplicaSet控制器、Ingress实现及PV/PVC存储等,这里就不再一一列举了。

如果需要在DC/OS集群上面卸载已安装的Kubernetes集群,建议在DC/OS界面上直接操作,不需要用DC/OS CLI 命令行的方工来操作!

留言

评论

${{item['author_name']}} 回复 ${{idToContentMap[item.parent] !== undefined ? idToContentMap[item.parent]['author_name'] : ''}} · ${{item.date.slice(0, 10)}} 回复

暂时还没有一条评论.