在CentOS 7上安装使用Kubernetes:管理云平台多个主机上的容器化应用

Table of Contents

安装Kubernetes Master和Minions

验证网络

ServiceAccount错误

玩K8S

运行Kubernetes留言簿(无GCE,无DNS)

在Kubernetes上运行多节点Galera Mysql

调试器Pod

为Kubernetes设置DNS

运行Heapster监视Kubernetes容器

运行Docker Registry

为C8S卷启用Ceph

K8S缺点的思考

推荐阅读


 

在本文中,我安装了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"

参考文献:[1] [2]

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_ADDRESSgcomm://每个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,下面是清单。在设置之前,我尝试了几种不同的清单。

这是从这里复制和编辑的。不要使用它。它的问题12534

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-systemdefault每个清单。

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):管理云平台中多个主机上的容器化的应用

 

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 酷酷鲨 设计师:CSDN官方博客 返回首页