BDOS 部署 Kubernetes 最佳实践
BDOS 部署 Kubernetes 最佳实践
需要的集群环境:已有BDOS DC/OS集群
BDOS版本号:v3.0
BDOS上面部署Kubernetes集群其架构图较简单,如下所示:
BDOS Kubernetes的安装部署
我们这里主要是通过自己BDOS 本地universe来进行安装和部署,这里需要进到DC/OS的界面,点击”Catalog”菜单,显示结果如下所示:
然后选中kubernetes,然后选择”Review Run”菜单,显示结果如下所示:
默认集成的Kubernetes集群是只有一个Node节点,这里可以根据实际集群资源情况来选择相应的节点数,如下所示:
由于这里是在Stage集群上测试,所以这里填写的是2,其它配置都选择默认即可,最后点击”Review&Run”菜单。
如果一切顺利和正常,最终的效果应该如下所示:
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中下载证书的实际操作如下:
- 直接通过wgt命令来下载kubectl命令行工具下载到当前目录,命令如下所示:
wget http://http://artifacts.linktime.cloud:8080/downloads/kubectl
- 使⽤用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 --- ---
- 使⽤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
命令显示结果如下所示:
然后可以用以下命令来查看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)}} 回复
暂时还没有一条评论.