在CentOS 7上安装使用Kubernetes:管理云平台多个主机上的容器化应用
在本文中,我安装了k8s集群,尝试设置托管真实Web服务所需的所有服务,然后进行总结。设置了一个主3小兵部署。如果使用的是vmware / virtualbox,请确保在vswitch上启用混杂模式。我没有实现HA。对于Kubernetes的HA部署,请参考官方的HA指南。
Table of Contents
在本文中,我安装了k8s集群,尝试设置托管真实Web服务所需的所有服务,然后进行总结。
安装Kubernetes Master和Minions
要安装Kubernetes,我遵循了Somenines的指南。注意
- 防火墙已关闭
- Kubernetes软件包的安装者
yum
- 我使用Kubernetes版本1.0
我设置了一个主3小兵部署。如果使用的是vmware / virtualbox,请确保在vswitch上启用混杂模式。我没有实现HA。对于Kubernetes的HA部署,请参考官方的HA指南。我的k8s版本如下
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"0+", GitVersion:"v1.0.0-290-gb2dafdaef5acea", GitCommit:"b2dafdaef5aceafad503ab56254b60f80da9e980", GitTreeState:"clean"}
Server Version: version.Info{Major:"1", Minor:"0+", GitVersion:"v1.0.0-290-gb2dafdaef5acea", GitCommit:"b2dafdaef5aceafad503ab56254b60f80da9e980", GitTreeState:"clean"}
$ uname -r
3.10.0-229.el7.x86_64
在主节点上启动服务
$ for SERVICES in etcd kube-apiserver kube-controller-manager kube-scheduler; do
systemctl restart $SERVICES
systemctl enable $SERVICES
systemctl status $SERVICES
done
在小仆节点上启动服务。请注意,我们需要比flanneld
早启动docker
,否则docker
可能不会使用法兰绒网络。
$ for SERVICES in kube-proxy kubelet flanneld docker; do # Launch flannel earilier than docker
systemctl restart $SERVICES
systemctl enable $SERVICES
systemctl status $SERVICES
done
验证网络
基本上,要让docker使用法兰绒网络,您需要添加--bip=${FLANNEL_SUBNET} --mtu=${FLANNEL_MTU}
到docker daemon启动选项。但是上面的安装将自动为您完成。
source /var/run/flannel/subnet.env
docker -d --bip=${FLANNEL_SUBNET} --mtu=${FLANNEL_MTU}
使用ps -ef|grep docker
检查泊坞窗守护进程选项。您应该能够看到docker需要法兰绒的Systemd单位文件
ps -ef | grep docker
cat /etc/systemd/system/docker.service.requires/flanneld.service
绒布网络运行后,每个主机上的每个容器都应使用不同的IP。他们应该能够ping通对方的IP地址。在下面使用以启动临时容器进行测试
docker run -d ubuntu:trusty /bin/bash -c "while true; do echo hello; sleep 10; done"
ServiceAccount错误
如果碰到下面的错误,取出ServiceAccount
的/etc/kubernetes/apiserver::KUBE_ADMISSION_CONTROL
。只需删除即可ServiceAccount
。(问题11222)。然后重新启动主节点。
$ kubectl create -f redis-master1.yaml
Error from server: error when creating "redis-master1.yaml": Pod "redis-master1" is forbidden: no API token found for service account default/default, retry after the token is automatically created and added to the service account
玩K8S
通过在k8s上设置一系列通用服务,我试图弄清楚如何在k8s上托管生产级别的网站。那里需要多节点数据库,卷,负载平衡,缓存(redis / memcached),dns和监视。
运行Kubernetes留言簿(无GCE,无DNS)
我正在使用kubernetes版本1.0。要在没有GCE,没有DNS的情况下仅在CentOS 7上运行留言簿。请遵循官方指南。
git clone https://github.com/kubernetes/kubernetes.git
cd kubernetes
git checkout 5adae4e4a35202abe1c130e32240d0461b3a1c36 # the version which I experimented with
创建Redis主Pod和服务
kubectl create -f examples/guestbook/redis-master-controller.yaml
kubectl get pods -o wide --all-namespaces=true
kubectl create -f examples/guestbook/redis-master-service.yaml
创建Redis奴隶
vim examples/guestbook/redis-slave-controller.yaml
... # comment out 'value: dns', uncomment `value: env` under GET_HOSTS_FROM
kubectl create -f examples/guestbook/redis-slave-controller.yaml
kubectl create -f examples/guestbook/redis-slave-service.yaml
kubectl logs redis-slave-* # should show successfully sync with master
创建前端控制器
vim examples/guestbook/frontend-controller.yaml
... # comment out 'value: dns', uncomment `value: env` under GET_HOSTS_FROM
kubectl create -f examples/guestbook/frontend-controller.yaml
kubectl create -f examples/guestbook/frontend-service.yaml
要在外部公开前端服务,我使用NodePort
。查看发布服务
vim examples/guestbook/frontend-services.yaml
... # Write `type: NodePort` under `spec`.
kubectl delete service frontend
kubectl create -f examples/guestbook/frontend-service.yaml
# to see which port is mapped
kubectl describe service frontend | grep NodePort # in my case the nodeport is 30363
你以后打开防火墙或iptables的,你应该能够从访问Web前端http://<any-minion-ip>:<nodeport>
。
签出redis中保存的内容
# on a k8s minion
$ docker exec -it k8s_worker.8bef144a_redis-slave-usfge_default_88895109-57a2-11e5-9a9e-005056957d30_3156e0e8 /bin/bash
$ redis-cli keys \*
1) "messages"
$ redis-cli get messages
",hello world,123,456"
或者只是通过Web浏览器获取它http://<any-minion-ip>:<nodeport>/guestbook.php?cmd=get&key=messages
。
在Kubernetes上运行多节点Galera Mysql
要在k8s上运行galera mysql,一种解决方案是Planet Mysql的解决方案(我认为博客内容与其代码库相比有些过时了)。检出其entrypoint.sh。关键是每个galera实例如何找到其他人的地址。Planet Mysql的解决方案使用k8s服务环境变量来定位其他主机并将其写入gcomm://
。每个mysql galera实例都包含一个pod和一个服务。
我可以想到的一些解决方案,可以帮助galera mysql实例定位其对等对象,除了Planet Mysql的
- 每个mysql galera实例都包含一个pod和一个服务。我们只是将IP地址硬编码在pod yaml中。如果一个pod掉了,我们手动填写最新的ip和启动一个新实例。
- 我们在k8s上启动一个etcd集群,所有galera mysql实例都从etcd找到对等信息。
无论如何,我现在将使用Planet Mysql的解决方案。PS除了galera之外,要托管mysql集群,还需要在k8s上提供mysql分片解决方案,例如youtube的Vitess Mysql。
首先,下载代码库
git clone https://github.com/CaptTofu/mysql_replication_kubernetes.git
cd mysql_replication_kubernetes
git checkout f7c2bc4f411d6950ca575e804189114026b2ba69 # the version I experimented with
cd galera_sync_replication
我认为我们应该根据容器映像的entrypoint.sh将所有设置WSREP_CLUSTER_ADDRESS
为gcomm://
每个pxc-nodeN 。
vim pxc-node1.yaml
... # change variable WSREP_CLUSTER_ADDRESS to gcomm://
vim pxc-node2.yaml
... # same as above
vim pxc-node3.yaml
... # same as above
接下来,我们逐一启动galera mysql实例
kubectl create -f pxc-node1.yaml
kubectl create -f pxc-node1-service.yaml
等待第一个galera mysql实例正在运行。比下面的发射。这是因为galera mysql需要至少运行一个实例来形成集群。
kubectl create -f pxc-node2.yaml
kubectl create -f pxc-node2-service.yaml
kubectl create -f pxc-node3.yaml
kubectl create -f pxc-node3-service.yaml
验证正确性。请参阅galera mysql状态指南。
# check the pod log
kubectl logs pxc-node3
# check galera mysql status
kubectl get pods -o wide
docker exec -it 98d568b88aac /bin/bash
mysql -uroot -p
mysql> SHOW GLOBAL STATUS LIKE 'wsrep_%'; # You should be able to see cluster_size = 3
# write something to mysql and check the other node reading it
...
我认为k8s服务设计可能不适用于galera mysql,redis,memcached等p2p集群。
- 在集群中,例如galera mysql,为什么要强制为每个实例耦合一个服务?
- 如果应用程序想要使用此类群集提供的服务(例如memcached),则需要知道它们的每个IP /主机名,因为一致的哈希,负载平衡和故障转移是在应用程序端执行的。很难仅将集群隐藏在一项服务下,该服务公开一个IP。
因此,我认为更合适的方法是从k8s外部提供这些服务,例如mysql,redis和memcached。但是,无状态Web应用程序更适合在k8s上运行。
调试器Pod
有时我需要一个简单的Pod来调试和测试与其他Pod的网络连接。这是我的豆荚yaml。
debugvm.yaml
apiVersion: v1
kind: Pod
metadata:
name: debugvm
labels:
name: debugvm
spec:
containers:
- name: debugvm
image: ubuntu:trusty
command: [ "bin/bash", "-c", "while true; do echo 'hello world'; sleep 60; done" ]
在k8s中启动后,登录到debugvm并使用nc测试到其他Pod的网络连接
docker exec -it k8s_debugvm.* /bin/bash
nc <host> <port>
运行多节点Redis以在Kubernetes上进行内存缓存
对于Web应用程序来说,使用Redis或Memcached群集作为内存中缓存非常流行。我启动一个3节点Redis集群。每个Redis都不知道其同级对象。每个redis实例都包含一个pod和一个服务。这是redis实例1
# the redis-master1.yaml
apiVersion: v1
kind: Pod
metadata:
name: redis-master1
labels:
name: redis-master1
spec:
containers:
- name: redis-master1
image: redis
ports:
- containerPort: 6379
# the redis-master1-service.yaml
apiVersion: v1
kind: Service
metadata:
name: redis-master1
labels:
name: redis-master1
spec:
ports:
# the default redis serving port
- port: 6379
targetPort: 6379
selector:
name: redis-master1
type: NodePort
对于redis实例2和3,只需将更1
改为2
或即可3
。Web应用程序要使用3个Redis实例作为缓存集群,需要自己执行一致的哈希并选择要访问的Redis实例。如果使用PHP,lib Predis可以做到这一点。
为什么我需要在每个Redis实例上附加一个k8s服务?客户端需要知道redis实例的每个IP并执行一致的哈希。但是,一个k8s服务仅在IP上公开。对于需要客户端分片/负载平衡/故障转移或任何客户端人员的群集,客户端需要了解更多IP。默认的k8s服务模型不太适合。
为Kubernetes设置DNS
Kuberetes可以使用dns服务进行服务发现。参见官方文档。DNS是一个k8s插件。我按照本指南设置了dns。该cluster_dns
地址应在/ etc / kubernetes / apiserver KUBE_SERVICE_ADDRESSES中指定的范围内。
# on each kubelet server
# add '--cluster_dns=10.254.0.10 --cluster_domain=cluster.local' to KUBELET_ARGS
vim /etc/kubernetes/kubelet
# restate kubelet
systemctl daemon-reload
systemctl restart kubelet
启动dns服务,下面是清单。从k8s repo复制和编辑。
apiVersion: v1
kind: Service
metadata:
name: kube-dns
namespace: default
labels:
k8s-app: kube-dns
kubernetes.io/cluster-service: "true"
kubernetes.io/name: "KubeDNS"
spec:
selector:
k8s-app: kube-dns
clusterIP: 10.254.0.10
ports:
- name: dns
port: 53
protocol: UDP
- name: dns-tcp
port: 53
protocol: TCP
启动dns pod,下面是清单。在设置之前,我尝试了几种不同的清单。
apiVersion: v1
kind: ReplicationController
metadata:
name: kube-dns
namespace: default
labels:
k8s-app: kube-dns
kubernetes.io/cluster-service: "true"
spec:
replicas: 1
selector:
k8s-app: kube-dns
template:
metadata:
labels:
k8s-app: kube-dns
kubernetes.io/cluster-service: "true"
spec:
dnsPolicy: "Default" # Don't use cluster DNS.
containers:
- name: etcd
image: quay.io/coreos/etcd:latest
command: [
"/etcd",
"--listen-client-urls",
"http://127.0.0.1:2379,http://127.0.0.1:4001",
"--advertise-client-urls",
"http://127.0.0.1:2379,http://127.0.0.1:4001",
]
- name: kube2sky
image: gcr.io/google_containers/kube2sky:1.11
args: [
# entrypoint = "/kube2sky",
"-domain=cluster.local",
]
- name: skydns
image: kubernetes/skydns:2014-12-23-001
args: [
# entrypoint = "/skydns",
"-machines=http://localhost:4001",
"-addr=0.0.0.0:53",
"-domain=cluster.local",
]
ports:
- name: dns
containerPort: 53
protocol: UDP
这是从k8s repo版本复制并编辑的。它具有相同的问题12534。
apiVersion: v1
kind: ReplicationController
metadata:
name: kube-dns-v9
namespace: default
labels:
k8s-app: kube-dns
version: v9
kubernetes.io/cluster-service: "true"
spec:
replicas: 1
selector:
k8s-app: kube-dns
version: v9
template:
metadata:
labels:
k8s-app: kube-dns
version: v9
kubernetes.io/cluster-service: "true"
spec:
containers:
- name: etcd
image: gcr.io/google_containers/etcd:2.0.9
resources:
limits:
cpu: 100m
memory: 50Mi
command:
- /usr/local/bin/etcd
- -data-dir
- /var/etcd/data
- -listen-client-urls
- http://127.0.0.1:2379,http://127.0.0.1:4001
- -advertise-client-urls
- http://127.0.0.1:2379,http://127.0.0.1:4001
- -initial-cluster-token
- skydns-etcd
volumeMounts:
- name: etcd-storage
mountPath: /var/etcd/data
- name: kube2sky
image: gcr.io/google_containers/kube2sky:1.11
resources:
limits:
cpu: 100m
memory: 50Mi
args:
# command = "/kube2sky"
- -domain=cluster.local
- name: skydns
image: gcr.io/google_containers/skydns:2015-03-11-001
resources:
limits:
cpu: 100m
memory: 50Mi
args:
# command = "/skydns"
- -machines=http://localhost:4001
- -addr=0.0.0.0:53
- -domain=cluster.local.
ports:
- containerPort: 53
name: dns
protocol: UDP
- containerPort: 53
name: dns-tcp
protocol: TCP
livenessProbe:
httpGet:
path: /healthz
port: 8080
scheme: HTTP
initialDelaySeconds: 30
timeoutSeconds: 5
readinessProbe:
httpGet:
path: /healthz
port: 8080
scheme: HTTP
initialDelaySeconds: 1
timeoutSeconds: 5
- name: healthz
image: gcr.io/google_containers/exechealthz:1.0
resources:
limits:
cpu: 10m
memory: 20Mi
args:
- -cmd=nslookup kubernetes.default.svc.cluster.local localhost >/dev/null
- -port=8080
ports:
- containerPort: 8080
protocol: TCP
volumes:
- name: etcd-storage
emptyDir: {}
dnsPolicy: Default # Don't use cluster DNS.
在研究了Guybrush的解决方案之后。我拼凑了一件作品。关键是缺少命令选项,-kube_master_url=http://<your-master-host-ip>:8080
该选项可防止kube2sky访问kubernetes主节点,并在12534中引发错误。简单。
apiVersion: v1
kind: ReplicationController
metadata:
name: kube-dns-v9
namespace: default
labels:
k8s-app: kube-dns
version: v9
kubernetes.io/cluster-service: "true"
spec:
replicas: 1
selector:
k8s-app: kube-dns
version: v9
template:
metadata:
labels:
k8s-app: kube-dns
version: v9
kubernetes.io/cluster-service: "true"
spec:
containers:
- name: etcd
image: gcr.io/google_containers/etcd:2.0.9
resources:
limits:
cpu: 100m
memory: 50Mi
command:
- /usr/local/bin/etcd
- -data-dir
- /var/etcd/data
- -listen-client-urls
- http://127.0.0.1:2379,http://127.0.0.1:4001
- -advertise-client-urls
- http://127.0.0.1:2379,http://127.0.0.1:4001
- -initial-cluster-token
- skydns-etcd
volumeMounts:
- name: etcd-storage
mountPath: /var/etcd/data
- name: kube2sky
image: gcr.io/google_containers/kube2sky:1.11
resources:
limits:
cpu: 100m
memory: 50Mi
args:
# command = "/kube2sky"
- -kube_master_url=http://10.62.98.245:8080
- -domain=cluster.local
- name: skydns
image: gcr.io/google_containers/skydns:2015-03-11-001
resources:
limits:
cpu: 100m
memory: 50Mi
args:
# command = "/skydns"
- -machines=http://localhost:4001
- -addr=0.0.0.0:53
- -domain=cluster.local.
ports:
- containerPort: 53
name: dns
protocol: UDP
- containerPort: 53
name: dns-tcp
protocol: TCP
livenessProbe:
httpGet:
path: /healthz
port: 8080
scheme: HTTP
initialDelaySeconds: 30
timeoutSeconds: 5
readinessProbe:
httpGet:
path: /healthz
port: 8080
scheme: HTTP
initialDelaySeconds: 1
timeoutSeconds: 5
- name: healthz
image: gcr.io/google_containers/exechealthz:1.0
resources:
limits:
cpu: 10m
memory: 20Mi
args:
- -cmd=nslookup kubernetes.default.svc.cluster.local localhost >/dev/null
- -port=8080
ports:
- containerPort: 8080
protocol: TCP
volumes:
- name: etcd-storage
emptyDir: {}
dnsPolicy: Default # Don't use cluster DNS.
要验证dns是否有效,我遵循了本指南。首先,您检查每个Pod日志以进行验证。但是如果您可以忽略此错误
skydns: falling back to default configuration, could not read from etcd: 100: Key not found (/skydns) [2]
之后,创建一个busybox窗格
# busybox.yaml
apiVersion: v1
kind: Pod
metadata:
name: busybox
namespace: default
spec:
containers:
- image: busybox
command:
- sleep
- "3600"
imagePullPolicy: IfNotPresent
name: busybox
restartPolicy: Always
在pod运行之后,运行以下命令,您应该会看到
$ kubectl exec busybox -- nslookup kubernetes
Server: 10.254.0.10
Address 1: 10.254.0.10
Name: kubernetes
Address 1: 10.254.0.1
$ kubectl exec busybox -- nslookup kubernetes.default.svc.cluster.local
Server: 10.254.0.10
Address 1: 10.254.0.10
Name: kubernetes.default.svc.cluster.local
Address 1: 10.254.0.1
运行Heapster监视Kubernetes容器
我遵循官方指南来设置Heapster。
git clone https://github.com/kubernetes/heapster.git
kubectl create -f deploy/kube-config/influxdb/
如果您遇到以下错误
Error from server: error when creating "deploy/kube-config/influxdb/grafana-service.json": Service "monitoring-grafana" is forbidden: Namespace kube-system does not exist
Error from server: error when creating "deploy/kube-config/influxdb/heapster-controller.json": ReplicationController "heapster" is forbidden: Namespace kube-system does not exist
Error from server: error when creating "deploy/kube-config/influxdb/heapster-service.json": Service "heapster" is forbidden: Namespace kube-system does not exist
Error from server: error when creating "deploy/kube-config/influxdb/influxdb-grafana-controller.json": ReplicationController "infludb-grafana" is forbidden: Namespace kube-system does not exist
Error from server: error when creating "deploy/kube-config/influxdb/influxdb-service.json": Service "monitoring-influxdb" is forbidden: Namespace kube-system does not exist
这是因为您的k8s没有kube-system
命名空间。解决方案是将所有内容都更改kube-system
为default
每个清单。
Heapster依靠k8s dns来工作。开始安装Heapster之前,必须先在k8s中启用dns。在这里发现类似的问题。
如果您检查heapster pod日志,发现heapster通过以下错误保持崩溃
$ kubectl logs heapster-yrh5i
...
open /var/run/secrets/kubernetes.io/serviceaccount/token: no such file or directory
问题在于,heapster缺少用于访问apiserver的serviceaccount。请参阅本指南。我的解决方案是“使用仅用于垃圾箱的服务帐户”。首先,在下面运行以创建服务帐户
cat <EOF | kubectl create -f -
apiVersion: v1
kind: ServiceAccount
metadata:
name: heapster
EOF
之后,需要添加serviceAccount: "heapster"
和--source=kubernetes:http://kubernetes-ro?inClusterConfig=false&useServiceAccount=true&auth=
规范。
"spec": {
"serviceAccount": "heapster",
"containers": [
{
"image": "kubernetes/heapster:v0.18.0",
"name": "heapster",
"command": [
"/heapster",
"--source=kubernetes:http://kubernetes-ro?inClusterConfig=false&useServiceAccount=true&auth=",
"--sink=influxdb:http://monitoring-influxdb:8086"
]
}
]
}
如果遇到以下错误
$ kubectl logs heapster-yrh5i
...
Failed to list *api.Node: Get http://kubernetes-ro/api/v1/nodes: dial tcp: lookup kubernetes-ro: no such host
Failed to list *api.Namespace: Get http://kubernetes-ro/api/v1/namespaces: dial tcp: lookup kubernetes-ro: no such host
Failed to list *api.Pod: Get http://kubernetes-ro/api/v1/pods?fieldSelector=spec.nodeName%21%3D: dial tcp: lookup kubernetes-ro: no such host
这是因为上面kubernetes-ro
的DNS无法解析。尝试kubectl exec busybox -- nslookup kubernetes-ro
验证。该线程指示kubernetes-ro
已弃用。因此将其更改为<kubeneters-master-ip>:8080
(我希望我可以避免对IP进行硬编码)。
{
"apiVersion": "v1",
"kind": "ReplicationController",
"metadata": {
"labels": {
"k8s-app" : "heapster",
"name": "heapster",
"version": "v6"
},
"name": "heapster",
"namespace": "default"
},
"spec": {
"replicas": 1,
"selector": {
"k8s-app": "heapster",
"version": "v6"
},
"template": {
"metadata": {
"labels": {
"k8s-app": "heapster",
"version": "v6"
}
},
"spec": {
"serviceAccount": "heapster",
"containers": [
{
"image": "kubernetes/heapster:v0.18.0",
"name": "heapster",
"command": [
"/heapster",
"--source=kubernetes:http://10.62.98.245:8080?inClusterConfig=false&useServiceAccount=true&auth=",
"--sink=influxdb:http://monitoring-influxdb:8086",
"-v=20"
]
}
]
}
}
}
}
接下来,我需要更改每个服务清单。将服务类型更改为“ NodePort”。这样,即使没有GCD负载平衡器,我仍然可以从外部访问它们。重新启动所有服务。
"spec": {
"type": "NodePort",
通过外部NodePort映射访问Grafana。用户名和密码为admin:admin。登录Grafana后,添加类型为InfluxDB 0.8.x
,url http://monitoring-influxdb:8086
,数据库名称为“ k8s”的数据源,数据库用户名和密码为root:root。
如果遇到以下错误,heapster将无法解析monitoring-influxdb,但是busybox仍然可以。那真是怪了。
$ kubectl logs heapster -k30m4
...
failed to sync data to sinks - encountered the following errors: Post http://monitoring-influxdb:8086/db/k8s/series?u=root&p=root&time_precision=s: dial tcp: lookup monitoring-influxdb: no such host ;
Post http://monitoring-influxdb:8086/db/k8s/series?u=root&p=root&time_precision=m: dial tcp: lookup monitoring-influxdb: no such host
# try troubleshooting. why busybox can resolve dns, but heapster cannot?
$ kubectl exec heapster-k30m4 -- nslookup monitoring-influxdb
Server: (null)
nslookup: can't resolve 'monitoring-influxdb': Try again
Address 1: ::1 localhost
Address 2: 127.0.0.1 localhost
$ kubectl exec busybox -- nslookup monitoring-influxdb
Server: 10.254.0.10
Address 1: 10.254.0.10
Name: monitoring-influxdb
Address 1: 10.254.113.143
$ kubectl exec heapster-k30m4 -- nslookup monitoring-influxdb 10.254.0.10
Server: 10.254.0.10
Address 1: 10.254.0.10
nslookup: can't resolve 'monitoring-influxdb': Try again
$ kubectl exec busybox -- nslookup monitoring-influxdb 10.254.0.10
Server: 10.254.0.10
Address 1: 10.254.0.10
Name: monitoring-influxdb
Address 1: 10.254.113.143
# check skydns log, found
$ kubectl logs kube-dns-v9-f9j9m skydns
...
skydns: can not forward, name too short (less than 2 labels): `monitoring-influxdb.'
我没有找到原因和解决方案。但是有一个解决方法,让我们直接将主机名写到/ etc / hosts中。
kubectl exec heapster-fk6xo -- /bin/sh -c 'echo ${MONITORING_INFLUXDB_SERVICE_HOST} monitoring-influxdb >> /etc/hosts'
kubectl exec infludb-grafana-9wosh -- /bin/sh -c 'echo ${MONITORING_INFLUXDB_SERVICE_HOST} monitoring-influxdb >> /etc/hosts'
现在,如果您检查堆日志,它应该可以正常工作。按照本指南,让我们回到Grafana来设置仪表板。示例查询在这里,但已经过时了。可以在influxdb上运行的一些查询是
select derivative(value/1000000) from "cpu/usage_ns_cumulative" where $timeFilter and container_name = 'pxc-node1' group by time($interval) order asc
select mean(value/1024/1024) from "memory/usage_bytes_gauge" where $timeFilter and container_name = 'pxc-node1' group by time($interval) order asc
有关如何使用influxdb的提示(在其门户网站上)
- root:root是集群管理员。创建数据库用户(管理员权限)并在访问数据库之前使用该用户登录。
- 不要将数据库用户设置为与集群管理员同名。否则会产生奇怪的许可。(天哪,这花了我很多时间进行故障排除)
- 用户
list series
看我们有什么表 - 带有特殊字符的系列名称,例如
cpu/limit_gauge
,应使用引号引起来,例如select * "cpu/limit_gauge" limit 10
where
子句中的字段名称应用单引号引起来,例如where container_name = 'pxc-node1'
在我设置Heapster时,无法收集容器网络io指标(始终为零)
- 知道问题待解决。在centos上
docker stats <container-id>
无法捕获网络io。
也无法在Heapster中收集磁盘io指标
- 知道问题。堆当前不拉磁盘io。
- 可以通过查询kubelet stats api(例如)来检索原始磁盘IO
curl 'http://<kubelet-ip>:10255/stats/default/pxc-node2/e2cf51fc-586e-11e5-9a9e-005056957d30/pxc-node2' | python -m json.tool
。该网址中的ID号可以在docker ps
容器名称中找到。 - 另一种方法是查询docker daemon套接字,例如
echo -e "GET /containers/<container-id>/stats HTTP/1.1\r\n" | nc -U /var/run/docker.sock | grep -e "^[[:space:]]*{.*}"
。看到这篇文章。 - 要了解diskio指标的含义,请注意,磁盘分区以Major:Minor号命名(
lsblk
请参见)。看这里。
运行Docker Registry
如果要构建自己的映像并在k8s上运行它们,则需要一个docker Registry。我在主节点上启动了Docker注册表,只需一行代码,请参阅官方指南。
docker run -d -p 5000:5000 --name registry registry:2
docker注册表应该现在正在运行。为了允许dockerd
使用“不安全”的Docker注册表,我们需要--insecure-registry <docker-registry>:5000
在每个节点上添加到/ etc / sysconfig / docker :: OPTIONS。dockerd
然后重新启动。
为C8S卷启用Ceph
Ceph为k8提供持久的批量服务。接下来,我将使k8s将ceph用作卷后端。
安装Ceph
我获取了一个新的centos7 VM,在其上安装了一个1节点的ceph。首先,请确保
- Kubernetes主节点和ceph节点无需密钥即可相互ssh
- Kubernetes主节点可以解析ceph节点的主机名
- 该
ceph-deploy
工具应在安装ceph的单独节点上运行
安装ceph-deploy
工具
# on kube master node
yum install -y ceph-deploy
mkdir -p ~/workspace/ceph/
cd ~/workspace/ceph
在ceph节点上安装并启动ceph。跟随官方教程
# on kube master node
# clean old installation
ceph-deploy purgedata <ceph-node>
ceph-deploy forgetkeys
#ceph-deploy purge # to purge the ceph packages too
# install ceph
ceph-deploy install <ceph-node>
# create the cluster
ceph-deploy new <ceph-node>
# change ceph config
vim ./ceph.conf
... # add `osd pool default size = 1`
# launch monitor
ceph-deploy mon create-initial
# launch osd
ceph-deploy disk list <ceph-node>
ceph-deploy osd prepare <ceph-node>:sdb
ceph-deploy osd activate <ceph-node>:/dev/sdb1
# push admin keys to the ceph node so that I can login without specifying monitor address and key file
ceph-deploy admin <ceph-node>
验证ceph的健康状态。
# on the ceph node
# test ceph healthy status
ceph health
ceph pg dump
# test ceph read write
ceph osd pool create data 128
echo hello world $(date) > test.txt
rados put test test.txt --pool data
rados get test test.txt.out --pool data
cat test.txt.out
接下来,在每个k8s节点上启用cephrbd
客户端
# on kube master node
# install ceph so that `rbd` is installed
ceph-deploy install 127.0.0.1 <kubelet1-ip> <kubelet2-ip> <kubelet3-ip>
# copy ceph admin keys to each node
cd ~/workspace/ceph
ceph-deploy admin 127.0.0.1 <kubelet1-ip> <kubelet2-ip> <kubelet3-ip>
验证rbd是否正常工作
# on a randomly picked up k8s node
rbd create foo --size 1024
modprobe rbd
rbd map foo
mkfs.ext4 -m0 /dev/rbd/rbd/foo
mkdir /mnt/test-ceph-block-device
mount /dev/rbd/rbd/foo /mnt/test-ceph-block-device
cd /mnt/test-ceph-block-device
echo hello world $(date) > test.txt
cd ..
umount /dev/rbd/rbd/foo
# on another k8s node
modprobe rbd
rbd map foo
mkdir /mnt/test-ceph-block-device
mount /dev/rbd/rbd/foo /mnt/test-ceph-block-device
cd /mnt/test-ceph-block-device
cat test.txt # here should print what we `echo` before
cd ..
umount /dev/rbd/rbd/foo
在K8S中启用Ceph
遵循官方指南。首先确保/etc/ceph/ceph.client.admin.keyring
每个k8s节点上都有k8s可以向ceph进行身份验证的操作系统。
vol1
在使用k8s之前,我们需要创建该卷并对其进行mkfs。
# on kube master node
rbd create vol1 --size 1024 --pool data
mkfs.ext4 -m0 /dev/rbd/data/vol1
rbd unmap /dev/rbd/data/vol1
接下来,我们创建一个忙碌的Pod来装载该卷。吊舱清单如下。开始于kubectl create -f busyboxv.yaml
# busyboxv.yaml
apiVersion: v1
kind: Pod
metadata:
name: busyboxv
namespace: default
spec:
containers:
- image: busybox
command:
- sleep
- "3600"
imagePullPolicy: IfNotPresent
name: busyboxv
volumeMounts:
- mountPath: /mnt/rbd
name: rbdpd
volumes:
- name: rbdpd
rbd:
monitors:
- <ceph-node>:6789
pool: data
image: vol1
user: admin
keyring: /etc/ceph/ceph.client.admin.keyring
fsType: ext4
readOnly: false
restartPolicy: Always
我们在busyboxv pod卷中写入一些文件
# on kube master node
kubectl exec busyboxv -- sh -c 'echo hello world $(date) > /mnt/rbd/hello.txt'
kubectl exec busyboxv -- sh -c 'cat /mnt/rbd/hello.txt'
接下来,杀死豆荚。测试卷中的数据是否持久
# on kube master node
kubectl delete pod busyboxv
sleep 5
rbd map vol1 --pool data
mkdir -p /mnt/rbd/data/vol1
mount /dev/rbd/data/vol1 /mnt/rbd/data/vol1
cat /mnt/rbd/data/vol1/hello.txt
umount /dev/rbd/data/vol1
rbd unmap /dev/rbd/data/vol1
因此,k8s pod可以通过这种方式使用ceph卷。现在我们有了持久的数据存储。
K8S缺点的思考
乍一看,Kubernetes看起来很简单。但是,根据这些天的经验,如果您想设置完整的Web服务,尤其是当您不在GCE(Google Cloud Engine)上运行时,我发现k8缺少许多关键功能:
-
如果我想使用外部或自定义负载均衡器(例如HAProxy)怎么办?Openstack具有LBaaS。但我希望在k8s中看到它。K8s服务可以进行负载平衡,但它不是功能齐全的负载平衡器。在GCE上运行k8s时,GCE为您提供了外部负载均衡器。但是,如果您自己运行k8s,则没有它。通过在Google上搜索,我发现人们已经开始为k8s建立自己的LB。
-
许多人在虚拟机上运行k8。VM覆盖网络和法兰绒覆盖网络将实际流量覆盖两次。这导致性能下降。Openstack Kuryr试图解决此问题。到那时,在Magnum上运行k8绝对是一个优势。
-
多租户需要网络分离。通过k8s网络模型,如果使用法兰绒,它将实际上连接每个容器,就好像它们在同一网络中一样。对于企业安全而言,这是不可接受的。但是,Openstack Neutron允许用户创建至少三个由L3分隔的网络,并通过路由器进行连接。
-
经典的k8s服务模型将一组Pod隐藏在服务后面,并向用户公开一个IP。但是,许多现实生活中的服务实际上并不适合该模型。下面的例子。解决方案是使用无头服务。参见[1] [2]。但是,用户仍然需要实现自己的服务发现并执行IP注册。它并不是真正的自动化。
-
Memcached或Redis作为缓存集群。客户端执行一致的哈希并决定要访问哪个Memcached或Redis实例。客户端需要知道每个实例的IP。如果您将整个Memcached或Redis群集隐藏在一项服务下,则不可能。一种解决方法是将每个实例附加到服务。
-
Mysql Galera群集。以类似的方式,客户端需要知道mysql实例的每个IP,以便它可以在一个实例关闭时进行故障转移。在k8s服务模型中,如果您将整个Mysql Galera群集隐藏在一项服务(同样在IP上)下,则不可能。
-
推荐阅读
《kubernetes(K8s):管理云平台中多个主机上的容器化的应用》
更多推荐
所有评论(0)