Kubernetes(k8s)总架构图及各组件介绍

一、Kubernetes的总架构图

未分类

二、Kubernetes各个组件介绍

(一)kube-master[控制节点]

master的工作流程图

未分类

  • Kubecfg将特定的请求,比如创建Pod,发送给Kubernetes Client。

  • Kubernetes Client将请求发送给API server。

  • API Server根据请求的类型,比如创建Pod时storage类型是pods,然后依此选择何种REST Storage API对请求作出处理。

  • REST Storage API对的请求作相应的处理。

  • 将处理的结果存入高可用键值存储系统Etcd中。

  • 在API Server响应Kubecfg的请求后,Scheduler会根据Kubernetes Client获取集群中运行Pod及Minion/Node信息。

  • 依据从Kubernetes Client获取的信息,Scheduler将未分发的Pod分发到可用的Minion/Node节点上。

1、API Server[资源操作入口]

  • 提供了资源对象的唯一操作入口,其他所有组件都必须通过它提供的API来操作资源数据,只有API Server与存储通信,其他模块通过API Server访问集群状态。

第一,是为了保证集群状态访问的安全。

第二,是为了隔离集群状态访问的方式和后端存储实现的方式:API Server是状态访问的方式,不会因为后端存储技术etcd的改变而改变。

  • 作为kubernetes系统的入口,封装了核心对象的增删改查操作,以RESTFul接口方式提供给外部客户和内部组件调用。对相关的资源数据“全量查询”+“变化监听”,实时完成相关的业务功能。

更多API Server信息请参考:Kubernetes核心原理(一)之API Server

2、Controller Manager[内部管理控制中心]

  • 实现集群故障检测和恢复的自动化工作,负责执行各种控制器,主要有:

endpoint-controller:定期关联service和pod(关联信息由endpoint对象维护),保证service到pod的映射总是最新的。

replication-controller:定期关联replicationController和pod,保证replicationController定义的复制数量与实际运行pod的数量总是一致的。

更多Controller Manager信息请参考:Kubernetes核心原理(二)之Controller Manager

3、Scheduler[集群分发调度器]

  • Scheduler收集和分析当前Kubernetes集群中所有Minion节点的资源(内存、CPU)负载情况,然后依此分发新建的Pod到Kubernetes集群中可用的节点。

  • 实时监测Kubernetes集群中未分发和已分发的所有运行的Pod。

  • Scheduler也监测Minion节点信息,由于会频繁查找Minion节点,Scheduler会缓存一份最新的信息在本地。

  • 最后,Scheduler在分发Pod到指定的Minion节点后,会把Pod相关的信息Binding写回API Server。

更多Scheduler信息请参考:Kubernetes核心原理(三)之Scheduler

(二)kube-node[服务节点]

kubelet结构图

未分类

1、Kubelet[节点上的Pod管家]

  • 负责Node节点上pod的创建、修改、监控、删除等全生命周期的管理

  • 定时上报本Node的状态信息给API Server。

  • kubelet是Master API Server和Minion之间的桥梁,接收Master API Server分配给它的commands和work,与持久性键值存储etcd、file、server和http进行交互,读取配置信息。

  • 具体的工作如下:

设置容器的环境变量、给容器绑定Volume、给容器绑定Port、根据指定的Pod运行一个单一容器、给指定的Pod创建network 容器。

同步Pod的状态、同步Pod的状态、从cAdvisor获取Container info、 pod info、 root info、 machine info。

在容器中运行命令、杀死容器、删除Pod的所有容器。

2、Proxy[负载均衡、路由转发]

  • Proxy是为了解决外部网络能够访问跨机器集群中容器提供的应用服务而设计的,运行在每个Node上。Proxy提供TCP/UDP sockets的proxy,每创建一种Service,Proxy主要从etcd获取Services和Endpoints的配置信息(也可以从file获取),然后根据配置信息在Minion上启动一个Proxy的进程并监听相应的服务端口,当外部请求发生时,Proxy会根据Load Balancer将请求分发到后端正确的容器处理。

  • Proxy不但解决了同一主宿机相同服务端口冲突的问题,还提供了Service转发服务端口对外提供服务的能力,Proxy后端使用了随机、轮循负载均衡算法。

3、kubectl(kubelet client)[集群管理命令行工具集]

通过客户端的kubectl命令集操作,API Server响应对应的命令结果,从而达到对kubernetes集群的管理。

kubernetes(k8s) 1.7.3 calico网络和Master ha安装说明

kubernetes 1.7.3

基于 二进制 文件部署 本地化 kube-apiserver, kube-controller-manager , kube-scheduler 我这边配置 既是 master 也是 nodes

环境说明

k8s-master-1: 10.6.0.140
k8s-master-2: 10.6.0.187
k8s-master-3: 10.6.0.188

初始化环境

hostnamectl --static set-hostname hostname

10.6.0.140 - k8s-master-1
10.6.0.187 - k8s-master-2
10.6.0.188 - k8s-master-3
#编辑 /etc/hosts 文件,配置hostname 通信

vi /etc/hosts

10.6.0.140 k8s-master-1
10.6.0.187 k8s-master-2
10.6.0.188 k8s-master-3

创建 验证

这里使用 CloudFlare 的 PKI 工具集 cfssl 来生成 Certificate Authority (CA) 证书和秘钥文件。

安装 cfssl

mkdir -p /opt/local/cfssl

cd /opt/local/cfssl

wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
mv cfssl_linux-amd64 cfssl

wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
mv cfssljson_linux-amd64 cfssljson

wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
mv cfssl-certinfo_linux-amd64 cfssl-certinfo

chmod +x *

创建 CA 证书配置

mkdir /opt/ssl

cd /opt/ssl

/opt/local/cfssl/cfssl print-defaults config > config.json

/opt/local/cfssl/cfssl print-defaults csr > csr.json
# config.json 文件

{
  "signing": {
    "default": {
      "expiry": "87600h"
    },
    "profiles": {
      "kubernetes": {
        "usages": [
            "signing",
            "key encipherment",
            "server auth",
            "client auth"
        ],
        "expiry": "87600h"
      }
    }
  }
}
# csr.json 文件

{
  "CN": "kubernetes",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "ShenZhen",
      "L": "ShenZhen",
      "O": "k8s",
      "OU": "System"
    }
  ]
}

生成 CA 证书和私钥

cd /opt/ssl/

/opt/local/cfssl/cfssl gencert -initca csr.json | /opt/local/cfssl/cfssljson -bare ca


[root@k8s-master-1 ssl]# ls -lt
总用量 20
-rw-r--r-- 1 root root 1005 7月   3 17:26 ca.csr
-rw------- 1 root root 1675 7月   3 17:26 ca-key.pem
-rw-r--r-- 1 root root 1363 7月   3 17:26 ca.pem
-rw-r--r-- 1 root root  210 7月   3 17:24 csr.json
-rw-r--r-- 1 root root  292 7月   3 17:23 config.json

分发证书

# 创建证书目录
mkdir -p /etc/kubernetes/ssl

# 拷贝所有文件到目录下
cp * /etc/kubernetes/ssl

# 这里要将文件拷贝到所有的k8s 机器上

scp * 10.6.0.187:/etc/kubernetes/ssl/

scp * 10.6.0.188:/etc/kubernetes/ssl/

etcd 集群

etcd 是k8s集群的基础组件

安装 etcd

yum -y install etcd

创建 etcd 证书

cd /opt/ssl/

vi etcd-csr.json

{
  "CN": "etcd",
  "hosts": [
    "127.0.0.1",
    "10.6.0.140",
    "10.6.0.187",
    "10.6.0.188"
  ],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "ShenZhen",
      "L": "ShenZhen",
      "O": "k8s",
      "OU": "System"
    }
  ]
}
# 生成 etcd   密钥

/opt/local/cfssl/cfssl gencert -ca=/opt/ssl/ca.pem 
  -ca-key=/opt/ssl/ca-key.pem 
  -config=/opt/ssl/config.json 
  -profile=kubernetes etcd-csr.json | /opt/local/cfssl/cfssljson -bare etcd
# 查看生成

[root@k8s-master-1 ssl]# ls etcd*
etcd.csr  etcd-csr.json  etcd-key.pem  etcd.pem
# 拷贝到etcd服务器

# etcd-1 
cp etcd*.pem /etc/kubernetes/ssl/

# etcd-2
scp etcd* 10.6.0.187:/etc/kubernetes/ssl/

# etcd-3
scp etcd* 10.6.0.188:/etc/kubernetes/ssl/



# 如果 etcd 非 root 用户,读取证书会提示没权限

chmod 644 /etc/kubernetes/ssl/etcd-key.pem

修改 etcd 配置

修改 etcd 启动文件 /usr/lib/systemd/system/etcd.service

# etcd-1


vi /usr/lib/systemd/system/etcd.service


[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target

[Service]
Type=notify
WorkingDirectory=/var/lib/etcd/
User=etcd
# set GOMAXPROCS to number of processors
ExecStart=/usr/bin/etcd 
  --name=etcd1 
  --cert-file=/etc/kubernetes/ssl/etcd.pem 
  --key-file=/etc/kubernetes/ssl/etcd-key.pem 
  --peer-cert-file=/etc/kubernetes/ssl/etcd.pem 
  --peer-key-file=/etc/kubernetes/ssl/etcd-key.pem 
  --trusted-ca-file=/etc/kubernetes/ssl/ca.pem 
  --peer-trusted-ca-file=/etc/kubernetes/ssl/ca.pem 
  --initial-advertise-peer-urls=https://10.6.0.140:2380 
  --listen-peer-urls=https://10.6.0.140:2380 
  --listen-client-urls=https://10.6.0.140:2379,http://127.0.0.1:2379 
  --advertise-client-urls=https://10.6.0.140:2379 
  --initial-cluster-token=k8s-etcd-cluster 
  --initial-cluster=etcd1=https://10.6.0.140:2380,etcd2=https://10.6.0.187:2380,etcd3=https://10.6.0.188:2380 
  --initial-cluster-state=new 
  --data-dir=/var/lib/etcd
Restart=on-failure
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
# etcd-2


vi /usr/lib/systemd/system/etcd.service


[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target

[Service]
Type=notify
WorkingDirectory=/var/lib/etcd/
User=etcd
# set GOMAXPROCS to number of processors
ExecStart=/usr/bin/etcd 
  --name=etcd2 
  --cert-file=/etc/kubernetes/ssl/etcd.pem 
  --key-file=/etc/kubernetes/ssl/etcd-key.pem 
  --peer-cert-file=/etc/kubernetes/ssl/etcd.pem 
  --peer-key-file=/etc/kubernetes/ssl/etcd-key.pem 
  --trusted-ca-file=/etc/kubernetes/ssl/ca.pem 
  --peer-trusted-ca-file=/etc/kubernetes/ssl/ca.pem 
  --initial-advertise-peer-urls=https://10.6.0.187:2380 
  --listen-peer-urls=https://10.6.0.187:2380 
  --listen-client-urls=https://10.6.0.187:2379,http://127.0.0.1:2379 
  --advertise-client-urls=https://10.6.0.187:2379 
  --initial-cluster-token=k8s-etcd-cluster 
  --initial-cluster=etcd1=https://10.6.0.140:2380,etcd2=https://10.6.0.187:2380,etcd3=https://10.6.0.188:2380 
  --initial-cluster-state=new 
  --data-dir=/var/lib/etcd
Restart=on-failure
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
# etcd-3


vi /usr/lib/systemd/system/etcd.service


[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target

[Service]
Type=notify
WorkingDirectory=/var/lib/etcd/
User=etcd
# set GOMAXPROCS to number of processors
ExecStart=/usr/bin/etcd 
  --name=etcd3 
  --cert-file=/etc/kubernetes/ssl/etcd.pem 
  --key-file=/etc/kubernetes/ssl/etcd-key.pem 
  --peer-cert-file=/etc/kubernetes/ssl/etcd.pem 
  --peer-key-file=/etc/kubernetes/ssl/etcd-key.pem 
  --trusted-ca-file=/etc/kubernetes/ssl/ca.pem 
  --peer-trusted-ca-file=/etc/kubernetes/ssl/ca.pem 
  --initial-advertise-peer-urls=https://10.6.0.188:2380 
  --listen-peer-urls=https://10.6.0.188:2380 
  --listen-client-urls=https://10.6.0.188:2379,http://127.0.0.1:2379 
  --advertise-client-urls=https://10.6.0.188:2379 
  --initial-cluster-token=k8s-etcd-cluster 
  --initial-cluster=etcd1=https://10.6.0.140:2380,etcd2=https://10.6.0.187:2380,etcd3=https://10.6.0.188:2380 
  --initial-cluster-state=new 
  --data-dir=/var/lib/etcd
Restart=on-failure
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

启动 etcd

分别启动 所有节点的 etcd 服务

systemctl enable etcd

systemctl start etcd

systemctl status etcd
# 如果报错 请使用
journalctl -f -t etcd  和 journalctl -u etcd 来定位问题

验证 etcd 集群状态

查看 etcd 集群状态:

etcdctl --endpoints=https://10.6.0.140:2379 
        --cert-file=/etc/kubernetes/ssl/etcd.pem 
        --ca-file=/etc/kubernetes/ssl/ca.pem 
        --key-file=/etc/kubernetes/ssl/etcd-key.pem 
        cluster-health

member 29262d49176888f5 is healthy: got healthy result from https://10.6.0.188:2379
member d4ba1a2871bfa2b0 is healthy: got healthy result from https://10.6.0.140:2379
member eca58ebdf44f63b6 is healthy: got healthy result from https://10.6.0.187:2379
cluster is healthy

查看 etcd 集群成员:

etcdctl --endpoints=https://10.6.0.140:2379 
        --cert-file=/etc/kubernetes/ssl/etcd.pem 
        --ca-file=/etc/kubernetes/ssl/ca.pem 
        --key-file=/etc/kubernetes/ssl/etcd-key.pem 
        member list


29262d49176888f5: name=etcd3 peerURLs=https://10.6.0.188:2380 clientURLs=https://10.6.0.188:2379 isLeader=false
d4ba1a2871bfa2b0: name=etcd1 peerURLs=https://10.6.0.140:2380 clientURLs=https://10.6.0.140:2379 isLeader=true
eca58ebdf44f63b6: name=etcd2 peerURLs=https://10.6.0.187:2380 clientURLs=https://10.6.0.187:2379 isLeader=false

安装 kubectl 工具

Master 端

# 首先安装 kubectl

wget https://dl.k8s.io/v1.7.3/kubernetes-client-linux-amd64.tar.gz

tar -xzvf kubernetes-client-linux-amd64.tar.gz

cp kubernetes/client/bin/* /usr/local/bin/

chmod a+x /usr/local/bin/kube*


# 验证安装

kubectl version
Client Version: version.Info{Major:"1", Minor:"7", GitVersion:"v1.7.3", GitCommit:"2c2fe6e8278a5db2d15a013987b53968c743f2a1", GitTreeState:"clean", BuildDate:"2017-08-03T07:00:21Z", GoVersion:"go1.8.3", Compiler:"gc", Platform:"linux/amd64"}
The connection to the server localhost:8080 was refused - did you specify the right host or port?

创建 admin 证书

kubectl 与 kube-apiserver 的安全端口通信,需要为安全通信提供 TLS 证书和秘钥。

cd /opt/ssl/

vi admin-csr.json


{
  "CN": "admin",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "ShenZhen",
      "L": "ShenZhen",
      "O": "system:masters",
      "OU": "System"
    }
  ]
}
# 生成 admin 证书和私钥
cd /opt/ssl/

/opt/local/cfssl/cfssl gencert -ca=/etc/kubernetes/ssl/ca.pem 
  -ca-key=/etc/kubernetes/ssl/ca-key.pem 
  -config=/etc/kubernetes/ssl/config.json 
  -profile=kubernetes admin-csr.json | /opt/local/cfssl/cfssljson -bare admin


# 查看生成

[root@k8s-master-1 ssl]# ls admin*
admin.csr  admin-csr.json  admin-key.pem  admin.pem

cp admin*.pem /etc/kubernetes/ssl/

scp admin*.pem 10.6.0.187:/etc/kubernetes/ssl/

scp admin*.pem 10.6.0.188:/etc/kubernetes/ssl/

配置 kubectl kubeconfig 文件

server 配置为 本机IP 各自连接本机的 Api

# 配置 kubernetes 集群

kubectl config set-cluster kubernetes 
  --certificate-authority=/etc/kubernetes/ssl/ca.pem 
  --embed-certs=true 
  --server=https://10.6.0.140:6443


# 配置 客户端认证

kubectl config set-credentials admin 
  --client-certificate=/etc/kubernetes/ssl/admin.pem 
  --embed-certs=true 
  --client-key=/etc/kubernetes/ssl/admin-key.pem



kubectl config set-context kubernetes 
  --cluster=kubernetes 
  --user=admin


kubectl config use-context kubernetes

kubectl config 文件

# kubeconfig 文件在 如下:

/root/.kube

部署 Kubernetes Master 节点

Master 需要部署 kube-apiserver , kube-scheduler , kube-controller-manager 这三个组件。

安装 组件

# 从github 上下载版本

cd /tmp

wget https://dl.k8s.io/v1.7.3/kubernetes-server-linux-amd64.tar.gz

tar -xzvf kubernetes-server-linux-amd64.tar.gz

cd kubernetes

cp -r server/bin/{kube-apiserver,kube-controller-manager,kube-scheduler,kubectl,kube-proxy,kubelet} /usr/local/bin/

创建 kubernetes 证书

cd /opt/ssl

vi kubernetes-csr.json

{
  "CN": "kubernetes",
  "hosts": [
    "127.0.0.1",
    "10.6.0.140",
    "10.6.0.187",
    "10.6.0.188",
    "10.254.0.1",
    "kubernetes",
    "kubernetes.default",
    "kubernetes.default.svc",
    "kubernetes.default.svc.cluster",
    "kubernetes.default.svc.cluster.local"
  ],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "ShenZhen",
      "L": "ShenZhen",
      "O": "k8s",
      "OU": "System"
    }
  ]
}


## 这里 hosts 字段中 三个 IP 分别为 127.0.0.1 本机, 10.6.0.140 和 10.6.0.187 为 Master 的IP,多个Master需要写多个 10.254.0.1 为 kubernetes SVC 的 IP, 一般是 部署网络的第一个IP , 如: 10.254.0.1 , 在启动完成后,我们使用   kubectl get svc , 就可以查看到

生成 kubernetes 证书和私钥

/opt/local/cfssl/cfssl gencert -ca=/etc/kubernetes/ssl/ca.pem 
  -ca-key=/etc/kubernetes/ssl/ca-key.pem 
  -config=/etc/kubernetes/ssl/config.json 
  -profile=kubernetes kubernetes-csr.json | /opt/local/cfssl/cfssljson -bare kubernetes

# 查看生成

[root@k8s-master-1 ssl]# ls -lt kubernetes*
-rw-r--r-- 1 root root 1245 7月   4 11:25 kubernetes.csr
-rw------- 1 root root 1679 7月   4 11:25 kubernetes-key.pem
-rw-r--r-- 1 root root 1619 7月   4 11:25 kubernetes.pem
-rw-r--r-- 1 root root  436 7月   4 11:23 kubernetes-csr.json


# 拷贝到目录
cp -r kubernetes* /etc/kubernetes/ssl/

scp -r kubernetes* 10.6.0.187:/etc/kubernetes/ssl/

scp -r kubernetes* 10.6.0.188:/etc/kubernetes/ssl/

配置 kube-apiserver

kubelet 首次启动时向 kube-apiserver 发送 TLS Bootstrapping 请求,kube-apiserver 验证 kubelet 请求中的 token 是否与它配置的 token 一致,如果一致则自动为 kubelet生成证书和秘钥。

# 生成 token

[root@k8s-master-1 ssl]# head -c 16 /dev/urandom | od -An -t x | tr -d ' '
10b459a82af1e16663f25061372fdab4


# 创建 token.csv 文件

cd /opt/ssl

vi token.csv

10b459a82af1e16663f25061372fdab4,kubelet-bootstrap,10001,"system:kubelet-bootstrap"


# 拷贝

cp token.csv /etc/kubernetes/

scp token.csv 10.6.0.187:/etc/kubernetes/

scp token.csv 10.6.0.188:/etc/kubernetes/

创建 kube-apiserver.service 文件

# 自定义 系统 service 文件一般存于 /etc/systemd/system/ 下
# 配置为 各自的本地 IP

vi /etc/systemd/system/kube-apiserver.service

[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=network.target

[Service]
User=root
ExecStart=/usr/local/bin/kube-apiserver 
  --admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota 
  --advertise-address=10.6.0.140 
  --allow-privileged=true 
  --apiserver-count=3 
  --audit-log-maxage=30 
  --audit-log-maxbackup=3 
  --audit-log-maxsize=100 
  --audit-log-path=/var/lib/audit.log 
  --authorization-mode=RBAC 
  --bind-address=10.6.0.140 
  --client-ca-file=/etc/kubernetes/ssl/ca.pem 
  --enable-swagger-ui=true 
  --etcd-cafile=/etc/kubernetes/ssl/ca.pem 
  --etcd-certfile=/etc/kubernetes/ssl/etcd.pem 
  --etcd-keyfile=/etc/kubernetes/ssl/etcd-key.pem 
  --etcd-servers=https://10.6.0.140:2379,https://10.6.0.187:2379,https://10.6.0.188:2379 
  --event-ttl=1h 
  --kubelet-https=true 
  --insecure-bind-address=10.6.0.140 
  --runtime-config=rbac.authorization.k8s.io/v1alpha1 
  --service-account-key-file=/etc/kubernetes/ssl/ca-key.pem 
  --service-cluster-ip-range=10.254.0.0/16 
  --service-node-port-range=30000-32000 
  --tls-cert-file=/etc/kubernetes/ssl/kubernetes.pem 
  --tls-private-key-file=/etc/kubernetes/ssl/kubernetes-key.pem 
  --experimental-bootstrap-token-auth 
  --token-auth-file=/etc/kubernetes/token.csv 
  --v=2
Restart=on-failure
RestartSec=5
Type=notify
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
# 这里面要注意的是 --service-node-port-range=30000-32000
# 这个地方是 映射外部端口时 的端口范围,随机映射也在这个范围内映射,指定映射端口必须也在这个范围内。

启动 kube-apiserver

systemctl daemon-reload
systemctl enable kube-apiserver
systemctl start kube-apiserver
systemctl status kube-apiserver

配置 kube-controller-manager

master 配置为 各自 本地 IP

# 创建 kube-controller-manager.service 文件

vi /etc/systemd/system/kube-controller-manager.service


[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/GoogleCloudPlatform/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-controller-manager 
  --address=127.0.0.1 
  --master=http://10.6.0.140:8080 
  --allocate-node-cidrs=true 
  --service-cluster-ip-range=10.254.0.0/16 
  --cluster-cidr=10.233.0.0/16 
  --cluster-name=kubernetes 
  --cluster-signing-cert-file=/etc/kubernetes/ssl/ca.pem 
  --cluster-signing-key-file=/etc/kubernetes/ssl/ca-key.pem 
  --service-account-private-key-file=/etc/kubernetes/ssl/ca-key.pem 
  --root-ca-file=/etc/kubernetes/ssl/ca.pem 
  --leader-elect=true 
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

启动 kube-controller-manager

systemctl daemon-reload
systemctl enable kube-controller-manager
systemctl start kube-controller-manager
systemctl status kube-controller-manager

配置 kube-scheduler

master 配置为 各自 本地 IP

# 创建 kube-cheduler.service 文件

vi /etc/systemd/system/kube-scheduler.service


[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/GoogleCloudPlatform/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-scheduler 
  --address=127.0.0.1 
  --master=http://10.6.0.140:8080 
  --leader-elect=true 
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

启动 kube-scheduler

systemctl daemon-reload
systemctl enable kube-scheduler
systemctl start kube-scheduler
systemctl status kube-scheduler

验证 Master 节点

[root@k8s-master-1 ~]# kubectl get componentstatuses
NAME                 STATUS    MESSAGE              ERROR
scheduler            Healthy   ok                   
controller-manager   Healthy   ok                   
etcd-0               Healthy   {"health": "true"}   
etcd-2               Healthy   {"health": "true"}   
etcd-1               Healthy   {"health": "true"} 



[root@k8s-master-2 ~]# kubectl get componentstatuses
NAME                 STATUS    MESSAGE              ERROR
controller-manager   Healthy   ok                   
scheduler            Healthy   ok                   
etcd-2               Healthy   {"health": "true"}   
etcd-0               Healthy   {"health": "true"}   
etcd-1               Healthy   {"health": "true"}  



[root@k8s-master-3 ~]# kubectl get componentstatuses
NAME                 STATUS    MESSAGE              ERROR
scheduler            Healthy   ok                   
controller-manager   Healthy   ok                   
etcd-0               Healthy   {"health": "true"}   
etcd-1               Healthy   {"health": "true"}   
etcd-2               Healthy   {"health": "true"}   

部署 Master Node 部分

Node 部分 需要部署的组件有 docker calico kubectl kubelet kube-proxy 这几个组件。

配置 kubelet

kubelet 启动时向 kube-apiserver 发送 TLS bootstrapping 请求,需要先将 bootstrap token 文件中的 kubelet-bootstrap 用户赋予 system:node-bootstrapper 角色,然后 kubelet 才有权限创建认证请求(certificatesigningrequests)。

# 先创建认证请求
# user 为 master 中 token.csv 文件里配置的用户
# 只需创建一次就可以

kubectl create clusterrolebinding kubelet-bootstrap --clusterrole=system:node-bootstrapper --user=kubelet-bootstrap

创建 kubelet kubeconfig 文件

server 配置为 master 本机 IP

# 配置集群

kubectl config set-cluster kubernetes 
  --certificate-authority=/etc/kubernetes/ssl/ca.pem 
  --embed-certs=true 
  --server=https://10.6.0.140:6443 
  --kubeconfig=bootstrap.kubeconfig

# 配置客户端认证

kubectl config set-credentials kubelet-bootstrap 
  --token=10b459a82af1e16663f25061372fdab4 
  --kubeconfig=bootstrap.kubeconfig


# 配置关联

kubectl config set-context default 
  --cluster=kubernetes 
  --user=kubelet-bootstrap 
  --kubeconfig=bootstrap.kubeconfig


# 配置默认关联
kubectl config use-context default --kubeconfig=bootstrap.kubeconfig

# 拷贝生成的 bootstrap.kubeconfig 文件

mv bootstrap.kubeconfig /etc/kubernetes/

创建 kubelet.service 文件

# 创建 kubelet 目录

> 配置为 node 本机 IP

mkdir /var/lib/kubelet

vi /etc/systemd/system/kubelet.service


[Unit]
Description=Kubernetes Kubelet
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=docker.service
Requires=docker.service

[Service]
WorkingDirectory=/var/lib/kubelet
ExecStart=/usr/local/bin/kubelet 
  --address=10.6.0.140 
  --hostname-override=10.6.0.140 
  --pod-infra-container-image=jicki/pause-amd64:3.0 
  --experimental-bootstrap-kubeconfig=/etc/kubernetes/bootstrap.kubeconfig 
  --kubeconfig=/etc/kubernetes/kubelet.kubeconfig 
  --require-kubeconfig 
  --cert-dir=/etc/kubernetes/ssl 
  --cluster_dns=10.254.0.2 
  --cluster_domain=cluster.local. 
  --hairpin-mode promiscuous-bridge 
  --allow-privileged=true 
  --serialize-image-pulls=false 
  --logtostderr=true 
  --v=2
ExecStopPost=/sbin/iptables -A INPUT -s 10.0.0.0/8 -p tcp --dport 4194 -j ACCEPT
ExecStopPost=/sbin/iptables -A INPUT -s 172.16.0.0/12 -p tcp --dport 4194 -j ACCEPT
ExecStopPost=/sbin/iptables -A INPUT -s 192.168.0.0/16 -p tcp --dport 4194 -j ACCEPT
ExecStopPost=/sbin/iptables -A INPUT -p tcp --dport 4194 -j DROP
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
# 如上配置:
10.6.0.140       为本机的IP
10.254.0.2       预分配的 dns 地址
cluster.local.   为 kubernetes 集群的 domain
jicki/pause-amd64:3.0  这个是 pod 的基础镜像,既 gcr 的 gcr.io/google_containers/pause-amd64:3.0 镜像, 下载下来修改为自己的仓库中的比较快。

启动 kubelet

systemctl daemon-reload
systemctl enable kubelet
systemctl start kubelet
systemctl status kubelet

配置 TLS 认证

# 查看 csr 的名称

[root@k8s-master-1 ~]# kubectl get csr
NAME                                                   AGE       REQUESTOR           CONDITION
node-csr-LkH2ZX9b2kACKmkNbp9PnK6BYAa5fMeh7nWtrGCipYc   58s       kubelet-bootstrap   Pending
node-csr-cxXvnzvukInZrSXT1EJTFaDzERFsuwsR2hCcgWyYZ2o   1m        kubelet-bootstrap   Pending
node-csr-jcQdD_haTRkPMTXwcHeyjQZUt2lb1S4rDeTgKUeQwgM   1m        kubelet-bootstrap   Pending


# 增加 认证

[root@k8s-master-1 ~]# kubectl certificate approve node-csr-LkH2ZX9b2kACKmkNbp9PnK6BYAa5fMeh7nWtrGCipYc
certificatesigningrequest "node-csr-LkH2ZX9b2kACKmkNbp9PnK6BYAa5fMeh7nWtrGCipYc" approved
[root@k8s-master-1 ~]# 
[root@k8s-master-1 ~]# kubectl certificate approve node-csr-cxXvnzvukInZrSXT1EJTFaDzERFsuwsR2hCcgWyYZ2o
certificatesigningrequest "node-csr-cxXvnzvukInZrSXT1EJTFaDzERFsuwsR2hCcgWyYZ2o" approved
[root@k8s-master-1 ~]# 
[root@k8s-master-1 ~]# kubectl certificate approve node-csr-jcQdD_haTRkPMTXwcHeyjQZUt2lb1S4rDeTgKUeQwgM
certificatesigningrequest "node-csr-jcQdD_haTRkPMTXwcHeyjQZUt2lb1S4rDeTgKUeQwgM" approved

验证 nodes

[root@k8s-master-1 ~]# kubectl get nodes
NAME         STATUS    AGE       VERSION
10.6.0.140   Ready     27s       v1.7.3
10.6.0.187   Ready     20s       v1.7.3
10.6.0.188   Ready     37s       v1.7.3


# 成功以后会自动生成配置文件与密钥

# 配置文件

ls /etc/kubernetes/kubelet.kubeconfig   
/etc/kubernetes/kubelet.kubeconfig


# 密钥文件

ls /etc/kubernetes/ssl/kubelet*
/etc/kubernetes/ssl/kubelet-client.crt  /etc/kubernetes/ssl/kubelet.crt
/etc/kubernetes/ssl/kubelet-client.key  /etc/kubernetes/ssl/kubelet.key

配置 kube-proxy

创建 kube-proxy 证书

# 证书方面由于我们node端没有装 cfssl
# 我们回到 master 端 机器 去配置证书,然后拷贝过来

[root@k8s-master-1 ~]# cd /opt/ssl


vi kube-proxy-csr.json

{
  "CN": "system:kube-proxy",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "ShenZhen",
      "L": "ShenZhen",
      "O": "k8s",
      "OU": "System"
    }
  ]
}

生成 kube-proxy 证书和私钥

/opt/local/cfssl/cfssl gencert -ca=/etc/kubernetes/ssl/ca.pem 
  -ca-key=/etc/kubernetes/ssl/ca-key.pem 
  -config=/etc/kubernetes/ssl/config.json 
  -profile=kubernetes  kube-proxy-csr.json | /opt/local/cfssl/cfssljson -bare kube-proxy

# 查看生成
ls kube-proxy*
kube-proxy.csr  kube-proxy-csr.json  kube-proxy-key.pem  kube-proxy.pem

# 拷贝到目录
cp kube-proxy*.pem /etc/kubernetes/ssl/

scp kube-proxy*.pem 10.6.0.187:/etc/kubernetes/ssl/

scp kube-proxy*.pem 10.6.0.188:/etc/kubernetes/ssl/

创建 kube-proxy kubeconfig 文件

server 配置为各自 本机IP

# 配置集群

kubectl config set-cluster kubernetes 
  --certificate-authority=/etc/kubernetes/ssl/ca.pem 
  --embed-certs=true 
  --server=https://10.6.0.140:6443 
  --kubeconfig=kube-proxy.kubeconfig


# 配置客户端认证

kubectl config set-credentials kube-proxy 
  --client-certificate=/etc/kubernetes/ssl/kube-proxy.pem 
  --client-key=/etc/kubernetes/ssl/kube-proxy-key.pem 
  --embed-certs=true 
  --kubeconfig=kube-proxy.kubeconfig


# 配置关联

kubectl config set-context default 
  --cluster=kubernetes 
  --user=kube-proxy 
  --kubeconfig=kube-proxy.kubeconfig



# 配置默认关联
kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig

# 拷贝到目录
mv kube-proxy.kubeconfig /etc/kubernetes/

创建 kube-proxy.service 文件

配置为 各自的 IP

# 创建 kube-proxy 目录

mkdir -p /var/lib/kube-proxy


vi /etc/systemd/system/kube-proxy.service

[Unit]
Description=Kubernetes Kube-Proxy Server
Documentation=https://github.com/GoogleCloudPlatform/kubernetes
After=network.target

[Service]
WorkingDirectory=/var/lib/kube-proxy
ExecStart=/usr/local/bin/kube-proxy 
  --bind-address=10.6.0.140 
  --hostname-override=10.6.0.140 
  --cluster-cidr=10.254.0.0/16 
  --kubeconfig=/etc/kubernetes/kube-proxy.kubeconfig 
  --logtostderr=true 
  --v=2
Restart=on-failure
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

启动 kube-proxy

systemctl daemon-reload
systemctl enable kube-proxy
systemctl start kube-proxy
systemctl status kube-proxy

部署 Node 节点

Node 节点 基于 Nginx 负载 API 做 Master HA

# master 之间除 api server 以外其他组件通过 etcd 选举,api server 默认不作处理;在每个 node 上启动一个 nginx,每个 nginx 反向代理所有 api server,node 上 kubelet、kube-proxy 连接本地的 nginx 代理端口,当 nginx 发现无法连接后端时会自动踢掉出问题的 api server,从而实现 api server 的 HA
cd /tmp

wget https://dl.k8s.io/v1.7.3/kubernetes-server-linux-amd64.tar.gz

tar -xzvf kubernetes-server-linux-amd64.tar.gz

cd kubernetes

cp -r server/bin/{kube-proxy,kubelet} /usr/local/bin/
# kubelet

# 首先 创建 kubelet kubeconfig 文件


kubectl config set-cluster kubernetes 
  --certificate-authority=/etc/kubernetes/ssl/ca.pem 
  --embed-certs=true 
  --server=https://127.0.0.1:6443 
  --kubeconfig=bootstrap.kubeconfig


# 配置客户端认证

kubectl config set-credentials kubelet-bootstrap 
  --token=10b459a82af1e16663f25061372fdab4 
  --kubeconfig=bootstrap.kubeconfig


# 配置关联

kubectl config set-context default 
  --cluster=kubernetes 
  --user=kubelet-bootstrap 
  --kubeconfig=bootstrap.kubeconfig


# 配置默认关联
kubectl config use-context default --kubeconfig=bootstrap.kubeconfig

# 拷贝生成的 bootstrap.kubeconfig 文件

mv bootstrap.kubeconfig /etc/kubernetes/
# 创建 kube-proxy kubeconfig 文件


kubectl config set-cluster kubernetes 
  --certificate-authority=/etc/kubernetes/ssl/ca.pem 
  --embed-certs=true 
  --server=https://127.0.0.1:6443 
  --kubeconfig=kube-proxy.kubeconfig


# 配置客户端认证

kubectl config set-credentials kube-proxy 
  --client-certificate=/etc/kubernetes/ssl/kube-proxy.pem 
  --client-key=/etc/kubernetes/ssl/kube-proxy-key.pem 
  --embed-certs=true 
  --kubeconfig=kube-proxy.kubeconfig


# 配置关联

kubectl config set-context default 
  --cluster=kubernetes 
  --user=kube-proxy 
  --kubeconfig=kube-proxy.kubeconfig



# 配置默认关联
kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig

# 拷贝到目录
mv kube-proxy.kubeconfig /etc/kubernetes/

创建Nginx 代理

在每个 node 都必须创建一个 Nginx 代理, 这里特别注意, 当 Master 也做为 Node 的时候 不需要配置 Nginx-proxy

# 创建配置目录
mkdir -p /etc/nginx

# 写入代理配置

cat << EOF >> /etc/nginx/nginx.conf
error_log stderr notice;

worker_processes auto;
events {
  multi_accept on;
  use epoll;
  worker_connections 1024;
}

stream {
    upstream kube_apiserver {
        least_conn;
        server 10.6.0.140:6443;
        server 10.6.0.187:6443;
        server 10.6.0.188:6443;
    }

    server {
        listen        0.0.0.0:6443;
        proxy_pass    kube_apiserver;
        proxy_timeout 10m;
        proxy_connect_timeout 1s;
    }
}
EOF
# 配置 Nginx 基于 docker 进程,然后配置 systemd 来启动

cat << EOF >> /etc/systemd/system/nginx-proxy.service

[Unit]
Description=kubernetes apiserver docker wrapper
Wants=docker.socket
After=docker.service

[Service]
User=root
PermissionsStartOnly=true
ExecStart=/usr/bin/docker run -p 6443:6443 \
                              -v /etc/nginx:/etc/nginx \
                              --name nginx-proxy \
                              --net=host \
                              --restart=on-failure:5 \
                              --memory=512M \
                              nginx:1.13.3-alpine
ExecStartPre=-/usr/bin/docker rm -f nginx-proxy
ExecStop=/usr/bin/docker stop nginx-proxy
Restart=always
RestartSec=15s
TimeoutStartSec=30s

[Install]
WantedBy=multi-user.target
EOF
# 启动 Nginx

systemctl daemon-reload
systemctl start nginx-proxy
systemctl enable nginx-proxy


# 重启 Node 的 kubelet 与 kube-proxy

systemctl restart kubelet
systemctl status kubelet

systemctl restart kube-proxy
systemctl status kube-proxy

Master 配置 TLS 认证

# 查看 csr 的名称

[root@k8s-master-1 ~]# kubectl get csr
NAME                                                   AGE       REQUESTOR           CONDITION
node-csr-LkH2ZX9b2kACKmkNbp9PnK6BYAa5fMeh7nWtrGCipYc   58s       kubelet-bootstrap   Pending
node-csr-cxXvnzvukInZrSXT1EJTFaDzERFsuwsR2hCcgWyYZ2o   1m        kubelet-bootstrap   Pending
node-csr-jcQdD_haTRkPMTXwcHeyjQZUt2lb1S4rDeTgKUeQwgM   1m        kubelet-bootstrap   Pending


# 增加 认证

[root@k8s-master-1 ~]# kubectl certificate approve node-csr-LkH2ZX9b2kACKmkNbp9PnK6BYAa5fMeh7nWtrGCipYc
certificatesigningrequest "node-csr-LkH2ZX9b2kACKmkNbp9PnK6BYAa5fMeh7nWtrGCipYc" approved
[root@k8s-master-1 ~]# 
[root@k8s-master-1 ~]# kubectl certificate approve node-csr-cxXvnzvukInZrSXT1EJTFaDzERFsuwsR2hCcgWyYZ2o
certificatesigningrequest "node-csr-cxXvnzvukInZrSXT1EJTFaDzERFsuwsR2hCcgWyYZ2o" approved
[root@k8s-master-1 ~]# 
[root@k8s-master-1 ~]# kubectl certificate approve node-csr-jcQdD_haTRkPMTXwcHeyjQZUt2lb1S4rDeTgKUeQwgM
certificatesigningrequest "node-csr-jcQdD_haTRkPMTXwcHeyjQZUt2lb1S4rDeTgKUeQwgM" approved

安装 docker

# 导入 yum 源

# 安装 yum-config-manager

yum -y install yum-utils

# 导入
yum-config-manager 
    --add-repo 
    https://download.docker.com/linux/centos/docker-ce.repo


# 更新 repo
yum makecache

# 安装

yum install docker-ce -y

更改docker 配置

# 修改配置

vi /usr/lib/systemd/system/docker.service

[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service
Wants=network-online.target

[Service]
Type=notify
ExecStart=/usr/bin/dockerd $DOCKER_NETWORK_OPTIONS $DOCKER_OPTS $DOCKER_DNS_OPTIONS
ExecReload=/bin/kill -s HUP $MAINPID
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TimeoutStartSec=0
Delegate=yes
KillMode=process
Restart=on-failure
StartLimitBurst=3
StartLimitInterval=60s

[Install]
WantedBy=multi-user.target
# 修改其他配置

mkdir -p /usr/lib/systemd/system/docker.service.d/


cat >> /usr/lib/systemd/system/docker.service.d/docker-options.conf << EOF
[Service]
Environment="DOCKER_OPTS=--insecure-registry=10.254.0.0/16 --graph=/opt/docker --registry-mirror=http://b438f72b.m.daocloud.io --iptables=false"
EOF
# 重新读取配置,启动 docker 
systemctl daemon-reload
systemctl start docker
systemctl enable docker

Calico 网络

修改 kubelet.service

vi /etc/systemd/system/kubelet.service

# 增加 如下配置

  --network-plugin=cni 


# 重新加载配置
systemctl daemon-reload
systemctl restart kubelet.service
systemctl status kubelet.service

修改 kube-proxy.service

vi /etc/systemd/system/kube-proxy.service

# 增加如下配置:
    --masquerade-all 

# 重新加载配置
systemctl daemon-reload
systemctl restart kube-proxy.service
systemctl status kube-proxy.service

安装 Calico

官网地址 http://docs.projectcalico.org/v2.3/getting-started/kubernetes/installation/hosted/hosted

# 下载 yaml 文件

wget http://docs.projectcalico.org/v2.3/getting-started/kubernetes/installation/hosted/calico.yaml

wget http://docs.projectcalico.org/v2.3/getting-started/kubernetes/installation/rbac.yaml


# 下载 镜像

# 国外镜像 有墙
quay.io/calico/node:v1.3.0
quay.io/calico/cni:v1.9.1
quay.io/calico/kube-policy-controller:v0.6.0


# 国内镜像
jicki/node:v1.3.0
jicki/cni:v1.9.1
jicki/kube-policy-controller:v0.6.0

配置 calico

vi calico.yaml

# 注意修改如下选项:


  etcd_endpoints: "https://10.6.0.140:2379,https://10.6.0.187:2379,https://10.6.0.188:2379"

    etcd_ca: "/calico-secrets/etcd-ca"  
    etcd_cert: "/calico-secrets/etcd-cert"
    etcd_key: "/calico-secrets/etcd-key"  


# 这里面要写入 base64 的信息



data:
  etcd-key: (cat /etc/kubernetes/ssl/etcd-key.pem | base64 | tr -d 'n')
  etcd-cert: (cat /etc/kubernetes/ssl/etcd.pem | base64 | tr -d 'n')
  etcd-ca: (cat /etc/kubernetes/ssl/ca.pem | base64 | tr -d 'n')


    - name: CALICO_IPV4POOL_CIDR
      value: "10.233.0.0/16"

导入 yaml 文件

[root@k8s-master-1 ~]# kubectl apply -f calico.yaml 
configmap "calico-config" created
secret "calico-etcd-secrets" created
daemonset "calico-node" created
deployment "calico-policy-controller" created
serviceaccount "calico-policy-controller" created
serviceaccount "calico-node" created


[root@k8s-master-1 ~]# kubectl apply -f rbac.yaml
clusterrole "calico-policy-controller" created
clusterrolebinding "calico-policy-controller" created
clusterrole "calico-node" created
clusterrolebinding "calico-node" created

验证 Calico

[root@k8s-master-1 ~]# kubectl get pods -n kube-system 
NAME                                       READY     STATUS    RESTARTS   AGE
calico-node-2dsq4                          2/2       Running   0          6m
calico-node-9ktvk                          2/2       Running   0          6m
calico-node-gwmx5                          2/2       Running   0          6m
calico-policy-controller-458850194-pn65p   1/1       Running   0          6m

安装 Calicoctl

cd /usr/local/bin/

wget -c  https://github.com/projectcalico/calicoctl/releases/download/v1.3.0/calicoctl

chmod +x calicoctl



## 创建 calicoctl 配置文件

# 配置文件, 在 安装了 calico 网络的 机器下

mkdir /etc/calico

vi /etc/calico/calicoctl.cfg


apiVersion: v1
kind: calicoApiConfig
metadata:
spec:
  datastoreType: "etcdv2"
  etcdEndpoints: "https://10.6.0.140:2379,https://10.6.0.187:2379,https://10.6.0.188:2379"
  etcdKeyFile: "/etc/kubernetes/ssl/etcd-key.pem"
  etcdCertFile: "/etc/kubernetes/ssl/etcd.pem"
  etcdCACertFile: "/etc/kubernetes/ssl/ca.pem"




# 查看 calico 状态

[root@k8s-master-1 ~]# calicoctl node status
Calico process is running.

IPv4 BGP status
+--------------+-------------------+-------+----------+-------------+
| PEER ADDRESS |     PEER TYPE     | STATE |  SINCE   |    INFO     |
+--------------+-------------------+-------+----------+-------------+
| 10.6.0.188   | node-to-node mesh | up    | 10:11:59 | Established |
| 10.6.0.187   | node-to-node mesh | up    | 10:16:32 | Established |
+--------------+-------------------+-------+----------+-------------+

IPv6 BGP status
No IPv6 peers found.

测试集群

# 创建一个 nginx deplyment

apiVersion: extensions/v1beta1 
kind: Deployment 
metadata: 
  name: nginx-dm
spec: 
  replicas: 2
  template: 
    metadata: 
      labels: 
        name: nginx 
    spec: 
      containers: 
        - name: nginx 
          image: nginx:alpine 
          imagePullPolicy: IfNotPresent
          ports: 
            - containerPort: 80

---

apiVersion: v1 
kind: Service
metadata: 
  name: nginx-svc 
spec: 
  ports: 
    - port: 80
      targetPort: 80
      protocol: TCP 
  selector: 
    name: nginx
[root@k8s-master-1 ~]# kubectl get pods
NAME                        READY     STATUS    RESTARTS   AGE
nginx-dm-2214564181-lxff5   1/1       Running   0          14m
nginx-dm-2214564181-qm1bp   1/1       Running   0          14m


[root@k8s-master-1 ~]# kubectl get deployment
NAME       DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx-dm   2         2         2            2           14m


[root@k8s-master-1 ~]# kubectl get svc
NAME         CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
kubernetes   10.254.0.1      <none>        443/TCP   4h
nginx-svc    10.254.129.54   <none>        80/TCP    15m
# 在 node 里 curl

[root@k8s-node-1 ~]# curl 10.254.129.54
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

配置 KubeDNS

官方 github yaml 相关 https://github.com/kubernetes/kubernetes/tree/master/cluster/addons/dns

下载镜像

# 官方镜像
gcr.io/google_containers/k8s-dns-sidecar-amd64:1.14.4
gcr.io/google_containers/k8s-dns-kube-dns-amd64:1.14.4
gcr.io/google_containers/k8s-dns-dnsmasq-nanny-amd64:1.14.4


# 我的镜像
jicki/k8s-dns-sidecar-amd64:1.14.4
jicki/k8s-dns-kube-dns-amd64:1.14.4
jicki/k8s-dns-dnsmasq-nanny-amd64:1.14.4

下载 yaml 文件

curl -O https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/dns/kubedns-cm.yaml


curl -O https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/dns/kubedns-sa.yaml


curl -O https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/dns/kubedns-controller.yaml.base


curl -O https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/dns/kubedns-svc.yaml.base


# 修改后缀

mv kubedns-controller.yaml.base kubedns-controller.yaml

mv kubedns-svc.yaml.base kubedns-svc.yaml

系统预定义的 RoleBinding

预定义的 RoleBinding system:kube-dns 将 kube-system 命名空间的 kube-dns ServiceAccount 与 system:kube-dns Role 绑定, 该 Role 具有访问 kube-apiserver DNS 相关 API 的权限;

[root@k8s-master-1 kubedns]# kubectl get clusterrolebindings system:kube-dns -o yaml
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  creationTimestamp: 2017-07-04T04:15:13Z
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: system:kube-dns
  resourceVersion: "106"
  selfLink: /apis/rbac.authorization.k8s.io/v1beta1/clusterrolebindings/system%3Akube-dns
  uid: 60c1e0e1-606f-11e7-b212-d4ae52d1f0c9
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:kube-dns
subjects:
- kind: ServiceAccount
  name: kube-dns
  namespace: kube-system

修改 kubedns-svc.yaml

# kubedns-svc.yaml 中 clusterIP: __PILLAR__DNS__SERVER__ 修改为我们之前定义的 dns IP 10.254.0.2

cat kubedns-svc.yaml

apiVersion: v1
kind: Service
metadata:
  name: kube-dns
  namespace: kube-system
  labels:
    k8s-app: kube-dns
    kubernetes.io/cluster-service: "true"
    addonmanager.kubernetes.io/mode: Reconcile
    kubernetes.io/name: "KubeDNS"
spec:
  selector:
    k8s-app: kube-dns
  clusterIP: 10.254.0.2
  ports:
  - name: dns
    port: 53
    protocol: UDP
  - name: dns-tcp
    port: 53
    protocol: TCP

修改 kubedns-controller.yaml

1. # 修改 --domain=__PILLAR__DNS__DOMAIN__.   为 我们之前 预定的 domain 名称 --domain=cluster.local.

2. # 修改 --server=/__PILLAR__DNS__DOMAIN__/127.0.0.1#10053  中 domain 为我们之前预定的 --server=/cluster.local./127.0.0.1#10053

3. # 修改 --probe=kubedns,127.0.0.1:10053,kubernetes.default.svc.__PILLAR__DNS__DOMAIN__, 中的 domain 为我们之前预定的  --probe=kubedns,127.0.0.1:10053,kubernetes.default.svc.cluster.local.,

4. # 修改 --probe=dnsmasq,127.0.0.1:53,kubernetes.default.svc.__PILLAR__DNS__DOMAIN__,  中的 domain 为我们之前预定的  --probe=dnsmasq,127.0.0.1:53,kubernetes.default.svc.cluster.local.,

导入 yaml 文件

# 替换所有的 images

sed -i 's/gcr.io/google_containers/jicki/g' *

# 导入

[root@k8s-master-1 kubedns]# kubectl create -f .
configmap "kube-dns" created
deployment "kube-dns" created
serviceaccount "kube-dns" created
service "kube-dns" created

查看 kubedns 服务

[root@k8s-master-1 kubedns]# kubectl get all --namespace=kube-system
NAME                                          READY     STATUS    RESTARTS   AGE
po/calico-node-2dsq4                          2/2       Running   0          15h
po/calico-node-9ktvk                          2/2       Running   0          15h
po/calico-node-gwmx5                          2/2       Running   0          15h
po/calico-policy-controller-458850194-pn65p   1/1       Running   0          15h
po/kube-dns-1511229508-jxkvs                  3/3       Running   0          4m

NAME           CLUSTER-IP   EXTERNAL-IP   PORT(S)         AGE
svc/kube-dns   10.254.0.2   <none>        53/UDP,53/TCP   4m

NAME                              DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deploy/calico-policy-controller   1         1         1            1           15h
deploy/kube-dns                   1         1         1            1           4m

NAME                                    DESIRED   CURRENT   READY     AGE
rs/calico-policy-controller-458850194   1         1         1         15h
rs/kube-dns-1511229508                  1         1         1         4m

验证 dns 服务

在验证 dns 之前,在 dns 未部署之前创建的 pod 与 deployment 等,都必须删除,重新部署,否则无法解析

# 导入之前的 nginx-dm yaml文件

[root@k8s-master-1 ~]# kubectl get pods -o wide
NAME                        READY     STATUS    RESTARTS   AGE       IP              NODE
nginx-dm-2214564181-0ctcx   1/1       Running   0          27s       10.233.168.1    10.6.0.188
nginx-dm-2214564181-brz79   1/1       Running   0          3m        10.233.196.2    10.6.0.140
nginx-dm-2214564181-z8whk   1/1       Running   0          3m        10.233.182.65   10.6.0.187

[root@k8s-master-1 ~]# kubectl get svc -o wide
NAME         CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE       SELECTOR
kubernetes   10.254.0.1     <none>        443/TCP   16h       <none>
nginx-svc    10.254.140.2   <none>        80/TCP    3m        name=nginx


# 创建一个 pods 来测试一下 nameserver

apiVersion: v1
kind: Pod
metadata:
  name: alpine
spec:
  containers:
  - name: alpine
    image: alpine
    command:
    - sh
    - -c
    - while true; do sleep 1; done



# 查看 pods
[root@k8s-master-1 ~]# kubectl get pods
NAME                        READY     STATUS    RESTARTS   AGE
alpine                      1/1       Running   0          5s
nginx-dm-2214564181-0ctcx   1/1       Running   0          7m
nginx-dm-2214564181-brz79   1/1       Running   0          10m
nginx-dm-2214564181-z8whk   1/1       Running   0          10m



# 测试

[root@k8s-master-1 ~]# kubectl exec -it alpine nslookup nginx-svc
nslookup: can't resolve '(null)': Name does not resolve

Name:      nginx-svc
Address 1: 10.254.140.2 nginx-svc.default.svc.cluster.local


[root@k8s-master-1 ~]# kubectl exec -it alpine ping nginx-svc    
PING nginx-svc (10.254.140.2): 56 data bytes

部署 Ingress 与 Dashboard

部署 dashboard && heapster

官方 dashboard 的github https://github.com/kubernetes/dashboard

下载 dashboard 镜像

# 官方镜像
gcr.io/google_containers/kubernetes-dashboard-amd64:v1.6.3

# 国内镜像
jicki/kubernetes-dashboard-amd64:v1.6.3

下载 yaml 文件

curl -O https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/dashboard/dashboard-controller.yaml


curl -O https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/dashboard/dashboard-service.yaml



# 因为开启了 RBAC 所以这里需要创建一个 RBAC 认证

vi dashboard-rbac.yaml


apiVersion: v1
kind: ServiceAccount
metadata:
  name: dashboard
  namespace: kube-system

---

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1alpha1
metadata:
  name: dashboard
subjects:
  - kind: ServiceAccount
    name: dashboard
    namespace: kube-system
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io

下载 heapster 镜像

# 官方文件
gcr.io/google_containers/heapster-amd64:v1.3.0
gcr.io/google_containers/heapster-influxdb-amd64:v1.1.1


# 本地文件
jicki/heapster-amd64:v1.3.0
jicki/heapster-influxdb-amd64:v1.1.1

下载 heapster 文件

官方网站 https://github.com/kubernetes/heapster/blob/master/docs/influxdb.md

curl -O https://raw.githubusercontent.com/kubernetes/heapster/master/deploy/kube-config/influxdb/influxdb.yaml

curl -O https://raw.githubusercontent.com/kubernetes/heapster/master/deploy/kube-config/influxdb/heapster.yaml

curl -O https://raw.githubusercontent.com/kubernetes/heapster/master/deploy/kube-config/rbac/heapster-rbac.yaml

修改 influxdb 配置

# influxdb.yaml 记录存储data数据

# 如下:

        volumeMounts:
        - mountPath: /data
          name: influxdb-storage
      volumes:
      - name: influxdb-storage
        emptyDir: {}


# volumes 请自行修改为 共享存储 或者 本地目录

导入 yaml

# 替换所有的 images

sed -i 's/gcr.io/google_containers/jicki/g' *




# dashboard-controller.yaml 增加 rbac 授权


# 在第二个 spec 下面 增加

    spec:
      serviceAccountName: dashboard



# 导入文件

[root@k8s-master-1 dashboard]# kubectl apply -f .
deployment "kubernetes-dashboard" created
serviceaccount "dashboard" created
clusterrolebinding "dashboard" created
service "kubernetes-dashboard" created



[root@k8s-master-1 heapster]# kubectl apply -f .
clusterrolebinding "heapster" created
serviceaccount "heapster" created
deployment "heapster" created
service "heapster" created
deployment "monitoring-influxdb" created
service "monitoring-influxdb" created



# 查看 svc 与 pod

[root@k8s-master-1 ~]# kubectl get svc -n kube-system
NAME                  CLUSTER-IP       EXTERNAL-IP   PORT(S)         AGE
heapster              10.254.231.18    <none>        80/TCP          13s
kube-dns              10.254.0.2       <none>        53/UDP,53/TCP   1h
monitoring-influxdb   10.254.240.245   <none>        8086/TCP        13s

部署 Nginx Ingress

Kubernetes 暴露服务的方式目前只有三种:LoadBlancer Service、NodePort Service、Ingress; 什么是 Ingress ? Ingress 就是利用 Nginx Haproxy 等负载均衡工具来暴露 Kubernetes 服务。

官方 Nginx Ingress github https://github.com/kubernetes/ingress/tree/master/examples/deployment/nginx

配置 调度 node

# ingress 有多种方式 1.  deployment 自由调度 replicas
                     2.  daemonset 全局调度 分配到所有node里


#  deployment 自由调度过程中,由于我们需要 约束 controller 调度到指定的 node 中,所以需要对 node 进行 label 标签


# 默认如下:
[root@k8s-master-1 ingress]# kubectl get nodes
NAME         STATUS    AGE       VERSION
10.6.0.140   Ready     18h       v1.7.3
10.6.0.187   Ready     18h       v1.7.3
10.6.0.188   Ready     18h       v1.7.3


# 对 140 与 187 打上 label

[root@k8s-master-1 ingress]# kubectl label nodes 10.6.0.140 ingress=proxy
node "10.6.0.140" labeled
[root@k8s-master-1 ingress]# kubectl label nodes 10.6.0.187 ingress=proxy
node "10.6.0.187" labeled


# 打完标签以后

[root@k8s-master-1 ingress]# kubectl get nodes --show-labels
NAME         STATUS    AGE       VERSION   LABELS
10.6.0.140   Ready     18h       v1.7.3    beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,ingress=proxy,kubernetes.io/hostname=10.6.0.140
10.6.0.187   Ready     18h       v1.7.3    beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,ingress=proxy,kubernetes.io/hostname=10.6.0.187
10.6.0.188   Ready     18h       v1.7.3    beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=10.6.0.188
# 下载镜像

# 官方镜像
gcr.io/google_containers/defaultbackend:1.0
gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.11

# 国内镜像
jicki/defaultbackend:1.0
jicki/nginx-ingress-controller:0.9.0-beta.11
# 部署 Nginx  backend , Nginx backend 用于统一转发 没有的域名 到指定页面。

curl -O https://raw.githubusercontent.com/kubernetes/ingress/master/examples/deployment/nginx/default-backend.yaml


# 直接导入既可, 这里不需要修改

[root@k8s-master-1 ingress]# kubectl apply -f default-backend.yaml 
deployment "default-http-backend" created
service "default-http-backend" created



# 查看服务
[root@k8s-master-1 ingress]# kubectl get deployment -n kube-system default-http-backend
NAME                   DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
default-http-backend   1         1         1            1           36s
# 部署 Ingress RBAC 认证

curl -O https://raw.githubusercontent.com/kubernetes/ingress/master/examples/rbac/nginx/nginx-ingress-controller-rbac.yml


# 修改 namespace

sed -i 's/namespace: nginx-ingress/namespace: kube-system/g' nginx-ingress-controller-rbac.yml


# 导入 yaml 文件

[root@k8s-master-1 ingress]# kubectl apply -f nginx-ingress-controller-rbac.yml 
namespace "nginx-ingress" created
serviceaccount "nginx-ingress-serviceaccount" created
clusterrole "nginx-ingress-clusterrole" created
role "nginx-ingress-role" created
rolebinding "nginx-ingress-role-nisa-binding" created
clusterrolebinding "nginx-ingress-clusterrole-nisa-binding" created
# 部署 Ingress Controller 组件

# 下载 yaml 文件

curl -O https://raw.githubusercontent.com/kubernetes/ingress/master/examples/deployment/nginx/nginx-ingress-controller.yaml

# 上面 对 两个 node 打了 label 所以配置 replicas: 2
# 修改 yaml 文件 增加 rbac 认证 , hostNetwork  还有 nodeSelector, 第二个 spec 下 增加。

spec:
  replicas: 2
  ....
    spec:
      hostNetwork: true
      serviceAccountName: nginx-ingress-serviceaccount
      nodeSelector:
        ingress: proxy
    ....
# 导入 yaml 文件

[root@k8s-master-1 ingress]# kubectl apply -f nginx-ingress-controller.yaml
deployment "nginx-ingress-controller" created


# 查看服务,可以看到这两个 pods 被分别调度到 140 与 187 中
[root@k8s-master-1 ingress]# kubectl get pods -n kube-system -o wide
NAME                                       READY     STATUS    RESTARTS   AGE       IP             NODE
nginx-ingress-controller-190167013-9j5kd   1/1       Running   0          45s       10.6.0.140     10.6.0.140
nginx-ingress-controller-190167013-n66qd   1/1       Running   0          45s       10.6.0.187     10.6.0.187
# 查看我们原有的 svc

[root@k8s-master-1 dashboard]# kubectl get svc -n kube-system kubernetes-dashboard
NAME                   CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
kubernetes-dashboard   10.254.243.198   <none>        80/TCP    21s


# 创建 yaml 文件

vi dashboard-ingress.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: dashboard-ingress
  namespaces: kube-system
spec:
  rules:
  - host: dashboard.jicki.me
    http:
      paths:
      - backend:
          serviceName: kubernetes-dashboard
          servicePort: 80



# 导入 yaml

[root@k8s-master-1 dashboard]# kubectl apply -f dashboard-ingress.yaml 
ingress "dashboard-ingress" created



# 查看 ingress

[root@k8s-master-1 dashboard]# kubectl get ingress -n kube-system -o wide
NAME                HOSTS                ADDRESS                 PORTS     AGE
dashboard-ingress   dashboard.jicki.me   10.6.0.140,10.6.0.187   80        1h


# 测试访问

[root@k8s-master-1 dashboard]# curl -I dashboard.jicki.me
HTTP/1.1 200 OK
Server: nginx/1.13.2
Date: Thu, 06 Jul 2017 06:32:00 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 848
Connection: keep-alive
Accept-Ranges: bytes
Cache-Control: no-store
Last-Modified: Tue, 16 May 2017 12:53:01 GMT

未分类

破坏性测试

破坏性测试,手动重启服务器,查看各服务间的恢复以及问题

[root@k8s-master-1 ~]# kubectl get nodes
NAME         STATUS    AGE       VERSION
10.6.0.140   Ready     20h       v1.7.3
10.6.0.187   Ready     20h       v1.7.3
10.6.0.188   Ready     20h       v1.7.3



[root@k8s-master-1 nginx]# etcdctl --endpoints=https://10.6.0.140:2379 
>         --cert-file=/etc/kubernetes/ssl/etcd.pem 
>         --ca-file=/etc/kubernetes/ssl/ca.pem 
>         --key-file=/etc/kubernetes/ssl/etcd-key.pem 
>         member list
2017-08-08 02:36:38.187672 I | warning: ignoring ServerName for user-provided CA for backwards compatibility is deprecated
29262d49176888f5: name=etcd3 peerURLs=https://10.6.0.188:2380 clientURLs=https://10.6.0.188:2379 isLeader=false
d4ba1a2871bfa2b0: name=etcd1 peerURLs=https://10.6.0.140:2380 clientURLs=https://10.6.0.140:2379 isLeader=true
eca58ebdf44f63b6: name=etcd2 peerURLs=https://10.6.0.187:2380 clientURLs=https://10.6.0.187:2379 isLeader=false


[root@k8s-master-1 ~]# reboot
PolicyKit daemon disconnected from the bus.
We are no longer a registered authentication agent.
# 服务器重启

[root@k8s-master-2 ~]# kubectl get nodes
NAME         STATUS     AGE       VERSION
10.6.0.140   NotReady   20h       v1.7.3
10.6.0.187   Ready      20h       v1.7.3
10.6.0.188   Ready      20h       v1.7.3



[root@k8s-master-2 ~]# etcdctl --endpoints=https://10.6.0.187:2379 
>         --cert-file=/etc/kubernetes/ssl/etcd.pem 
>         --ca-file=/etc/kubernetes/ssl/ca.pem 
>         --key-file=/etc/kubernetes/ssl/etcd-key.pem 
>         member list
2017-08-08 02:34:00.132653 I | warning: ignoring ServerName for user-provided CA for backwards compatibility is deprecated
29262d49176888f5: name=etcd3 peerURLs=https://10.6.0.188:2380 clientURLs=https://10.6.0.188:2379 isLeader=false
d4ba1a2871bfa2b0: name=etcd1 peerURLs=https://10.6.0.140:2380 clientURLs=https://10.6.0.140:2379 isLeader=false
eca58ebdf44f63b6: name=etcd2 peerURLs=https://10.6.0.187:2380 clientURLs=https://10.6.0.187:2379 isLeader=true



# 等待服务器重启以后

[root@k8s-master-2 ~]# kubectl get nodes
NAME         STATUS    AGE       VERSION
10.6.0.140   Ready     20h       v1.7.3
10.6.0.187   Ready     20h       v1.7.3
10.6.0.188   Ready     20h       v1.7.3


[root@k8s-master-2 ~]# kubectl get pods -o wide
NAME                        READY     STATUS    RESTARTS   AGE       IP              NODE
alpine                      1/1       Running   1          4h        10.233.196.8    10.6.0.140
nginx-dm-2214564181-0ctcx   1/1       Running   0          4h        10.233.168.4    10.6.0.188
nginx-dm-2214564181-brz79   1/1       Running   1          4h        10.233.196.7    10.6.0.140
nginx-dm-2214564181-z8whk   1/1       Running   0          4h        10.233.182.65   10.6.0.187


[root@k8s-master-2 ~]# etcdctl --endpoints=https://10.6.0.140:2379 
>         --cert-file=/etc/kubernetes/ssl/etcd.pem 
>         --ca-file=/etc/kubernetes/ssl/ca.pem 
>         --key-file=/etc/kubernetes/ssl/etcd-key.pem 
>         member list
2017-08-08 02:39:52.830072 I | warning: ignoring ServerName for user-provided CA for backwards compatibility is deprecated
29262d49176888f5: name=etcd3 peerURLs=https://10.6.0.188:2380 clientURLs=https://10.6.0.188:2379 isLeader=true
d4ba1a2871bfa2b0: name=etcd1 peerURLs=https://10.6.0.140:2380 clientURLs=https://10.6.0.140:2379 isLeader=false
eca58ebdf44f63b6: name=etcd2 peerURLs=https://10.6.0.187:2380 clientURLs=https://10.6.0.187:2379 isLeader=false

Kubernetes(k8s) EmptyDir、HostPath、ConfigMap和Secret等几种存储类型介绍

一个运行中的容器,缺省情况下,对文件系统的写入,都是发生在其分层文件系统的可写层的,一旦容器运行结束,所有写入都会被丢弃。因此需要对持久化支持。

Kubernetes 中通过 Volume 的方式提供对存储的支持。下面对一些常见的存储概念进行一点简要的说明。

EmptyDir

顾名思义,EmptyDir是一个空目录,他的生命周期和所属的 Pod 是完全一致的,可能读者会奇怪,那还要他做什么?EmptyDir的用处是,可以在同一 Pod 内的不同容器之间共享工作过程中产生的文件。

缺省情况下,EmptyDir 是使用主机磁盘进行存储的,也可以设置emptyDir.medium 字段的值为Memory,来提高运行速度,但是这种设置,对该卷的占用会消耗容器的内存份额。

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: gcr.io/google_containers/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
  - name: cache-volume
    emptyDir: {}

HostPath

这种会把宿主机上的指定卷加载到容器之中,当然,如果 Pod 发生跨主机的重建,其内容就难保证了。

这种卷一般和DaemonSet搭配使用,用来操作主机文件,例如进行日志采集的 FLK 中的 FluentD 就采用这种方式,加载主机的容器日志目录,达到收集本主机所有日志的目的。

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: gcr.io/google_containers/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /test-pd
      name: test-volume
  volumes:
  - name: test-volume
    hostPath:
      # directory location on host
      path: /data

NFS/GlusterFS/CephFS/AWS/GCE 等等

作为一个容器集群,支持网络存储自然是重中之重了,Kubernetes 支持为数众多的云提供商和网络存储方案。

各种支持的方式不尽相同,例如 GlusterFS 需要创建 Endpoint,Ceph/NFS 之流就没这么麻烦了。

各种个性配置可移步参考文档。

ConfigMap 和 Secret

镜像使用的过程中,经常需要利用配置文件、启动脚本等方式来影响容器的运行方式,如果仅有少量配置,我们可以使用环境变量的方式来进行配置。然而对于一些较为复杂的配置,例如 Apache 之类,就很难用这种方式进行控制了。另外一些敏感信息暴露在 YAML 中也是不合适的。

ConfigMap 和 Secret 除了使用文件方式进行应用之外,还有其他的应用方式;这里仅就文件方式做一点说明。

例如下面的 ConfigMap,将一个存储在 ConfigMap 中的配置目录加载到卷中。

apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod
spec:
  containers:
    - name: test-container
      image: gcr.io/google_containers/busybox
      command: [ "/bin/sh", "-c", "ls /etc/config/" ]
      volumeMounts:
      - name: config-volume
        mountPath: /etc/config
  volumes:
    - name: config-volume
      configMap:
        # Provide the name of the ConfigMap containing the files you want
        # to add to the container
        name: special-config
  restartPolicy: Never

注意,这里的 ConfigMap 会映射为一个目录,ConfigMap 的 Key 就是文件名,每个 Value 就是文件内容,比如下面命令用一个目录创建一个 ConfigMap:

kubectl create configmap 
    game-config 
    --from-file=docs/user-guide/configmap/kubectl

创建一个 Secret:

kubectl create secret generic 
    db-user-pass --from-file=./username.txt 
    --from-file=./password.txt

使用 Volume 加载 Secret:

apiVersion: v1
kind: Pod
metadata:
  name: mypod
  namespace: myns
spec:
  containers:
    - name: mypod
      image: redis
      volumeMounts:
        - name: foo
          mountPath: /etc/foo
          readOnly: true
  volumes:
    - name: foo
      secret:
        secretName: mysecret

可以看到 Secret 和 ConfigMap 的创建和使用是很相似的。在 RBAC 中,Secret 和 ConfigMap 可以进行分别赋权,以此限定操作人员的可见、可控权限。

PV & PVC

PersistentVolume 和 PersistentVolumeClaim 提供了对存储支持的抽象,也提供了基础设施和应用之间的分界,管理员创建一系列的 PV 提供存储,然后为应用提供 PVC,应用程序仅需要加载一个 PVC,就可以进行访问。

而 1.5 之后又提供了 PV 的动态供应。可以不经 PV 步骤直接创建 PVC。

k8s(kubernetes)kube-proxy转发模式及service端口类型介绍

配置方式

kubernetes版本大于或者等于1.2时,外部网络(即非K8S集群内的网络)访问cluster IP的办法是:

修改master的/etc/kubernetes/proxy,把KUBE_PROXY_ARGS=”“改为KUBE_PROXY_ARGS=”–proxy-mode=userspace”
启动kube-proxy服务
在核心路由设备或者源主机上添加一条路由,访问cluster IP段的路由指向到master上。

kubernetes版本小于1.2时,直接添加路由

未分类

kube-proxy转发的两种模式

kube-proxy在转发时主要有两种模式Userspace和Iptables。如下图,左侧是Userspace模式,也是kube-proxy默认的方式,所有的转发都是通过kube-proxy软件实现的;右侧是Iptables模式,所有转发都是通过Iptables内核模块实现,而kube-proxy只负责生成相应的Iptables规则。

未分类

使用Userspace模式(k8s版本为1.2之前默认模式),外部网络可以直接访问cluster IP。
使用Iptables模式(k8s版本为1.2之后默认模式),外部网络不能直接访问cluster IP。
从效率上看,Iptables会更高一些,但是需要Iptables version >=1.4.11,Iptables模式在k8s1.2版本放出。

service转发后端服务的四种类型

ClusterIP

此类型会提供一个集群内部的虚拟IP(与Pod不在同一网段),以供集群内部的pod之间通信使用。ClusterIP也是Kubernetes service的默认类型。

未分类

为了实现图上的功能主要需要以下几个组件的协同工作:

  • apiserver:在创建service时,apiserver接收到请求以后将数据存储到etcd中。
  • kube-proxy:k8s的每个节点中都有该进程,负责实现service功能,这个进程负责感知service,pod的变化,并将变化的信息写入本地的iptables中。
  • iptables:使用NAT等技术将virtualIP的流量转至endpoint中。

NodePort

NodePort模式除了使用cluster ip外,也将service的port映射到每个node的一个指定内部port上,映射的每个node的内部port都一样。
为每个节点暴露一个端口,通过nodeip + nodeport可以访问这个服务,同时服务依然会有cluster类型的ip+port。内部通过clusterip方式访问,外部通过nodeport方式访问。

未分类

loadbalance

LoadBalancer在NodePort基础上,K8S可以请求底层云平台创建一个负载均衡器,将每个Node作为后端,进行服务分发。该模式需要底层云平台(例如GCE)支持。

Ingress

Ingress,是一种HTTP方式的路由转发机制,由Ingress Controller和HTTP代理服务器组合而成。Ingress Controller实时监控Kubernetes API,实时更新HTTP代理服务器的转发规则。HTTP代理服务器有GCE Load-Balancer、HaProxy、Nginx等开源方案。

详细说明请见http://blog.csdn.net/liyingke112/article/details/77066814

未分类

service的三种端口

port

service暴露在cluster ip上的端口,:port 是提供给集群内部客户访问service的入口。

nodePort

nodePort是k8s提供给集群外部客户访问service入口的一种方式,:nodePort 是提供给集群外部客户访问service的入口。

targetPort

targetPort是pod上的端口,从port和nodePort上到来的数据最终经过kube-proxy流入到后端pod的targetPort上进入容器。

port、nodePort总结

总的来说,port和nodePort都是service的端口,前者暴露给集群内客户访问服务,后者暴露给集群外客户访问服务。从这两个端口到来的数据都需要经过反向代理kube-proxy流入后端pod的targetPod,从而到达pod上的容器内。

ubuntu 16.04 k8s(kubernetes) delve debug环境配置

环境说明

  • 系统:ubuntu 16.04
  • k8s版本:1.5.7
  • 内存:8GB

Docker安装

1. 卸载旧版本

sudo apt-get remove docker docker-engine docker.io

2. 配置仓库

apt-get update
apt-get -y install 
    apt-transport-https 
    ca-certificates 
    curl 
    software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
apt-key fingerprint 0EBFCD88
add-apt-repository 
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu 
   $(lsb_release -cs) 
   stable"

3. 安装docker ce

apt-get update
apt-cache madison docker-ce
apt-get -y install docker-ce=17.06.0~ce-0~ubuntu

etcd安装

1. 安装

ETCD_VER=v3.2.5
# choose either URL
GOOGLE_URL=https://storage.googleapis.com/etcd
GITHUB_URL=https://github.com/coreos/etcd/releases/download
DOWNLOAD_URL=${GOOGLE_URL}

rm -f /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz
rm -rf /opt/etcd-${ETCD_VER} && mkdir -p /opt/etcd-${ETCD_VER}

curl -L ${DOWNLOAD_URL}/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz -o /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz
tar xzvf /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz -C /opt/etcd-${ETCD_VER} --strip-components=1
/opt/etcd-${ETCD_VER}/etcd --version

2. 环境变量

echo "export PATH=/opt/etcd-${ETCD_VER}:$PATH" >> /etc/profile

go安装

1. 下载go

cd /usr/local
wget https://storage.googleapis.com/golang/go1.9rc2.linux-amd64.tar.gz
tar xf go1.9rc2.linux-amd64.tar.gz
mkdir -p /home/go

2. 环境变量

echo 'export PATH=/usr/local/go/bin:$PATH' >> /etc/profile
echo "export GOPATH=/home/go" >> /etc/profile

OpenSSL安装

apt-get -y install openssl

安装k8s

安装

apt-get -y install unzip make gccgo
cd /home/go
wget https://github.com/kubernetes/kubernetes/archive/v1.5.7.zip
unzip v1.5.7.zip 
cd kubernetes-1.5.7
. /etc/profile
make GOGCFLAGS="-N -l"

启动

./hack/local-up-cluster.sh -O

配置

export KUBERNETES_PROVIDER=local
cluster/kubectl.sh config set-cluster local --server=https://localhost:6443 --certificate-authority=/var/run/kubernetes/apiserver.crt
cluster/kubectl.sh config set-credentials myself --username=admin --password=admin
cluster/kubectl.sh config set-context local --cluster=local --user=myself
cluster/kubectl.sh config use-context local
cluster/kubectl.sh

安装delve

go get github.com/derekparker/delve/cmd/dlv
cd /home/go/src/github.com/derekparker/delve
echo 'export PATH="$GOPATH/bin:$PATH' >> /etc/profile
. /etc/profile

dlv debug

启动

dlv exec /home/go/kubernetes-1.5.7/_output/bin/kubectl -- run my-nginx --image=nginx --replicas=2 --port=80

设置断点

(dlv) b cmd/run.go:138
Breakpoint 1 set at 0x1c3a45b for k8s.io/kubernetes/pkg/kubectl/cmd.Run() ./kubernetes-1.5.7/_output/local/go/src/k8s.io/kubernetes/pkg/kubectl/cmd/run.go:138

前进到断点

(dlv) c
> k8s.io/kubernetes/pkg/kubectl/cmd.Run() ./kubernetes-1.5.7/_output/local/go/src/k8s.io/kubernetes/pkg/kubectl/cmd/run.go:138 (hits goroutine(1):1 total:1) (PC: 0x1c3a45b)
   133:         cmd.Flags().String("service-overrides", "", "An inline JSON override for the generated service object. If this is non-empty, it is used to override the generated object. Requires that the object supply a valid apiVersion field.  Only used if --expose is true.")
   134:         cmd.Flags().Bool("quiet", false, "If true, suppress prompt messages.")
   135:         cmd.Flags().String("schedule", "", "A schedule in the Cron format the job should be run with.")
   136: }
   137:
=> 138: func Run(f cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *cobra.Command, args []string, argsLenAtDash int) error {
   139:         if len(os.Args) > 1 && os.Args[1] == "run-container" {
   140:                 printDeprecationWarning("run", "run-container")
   141:         }
   142:
   143:         // Let kubectl run follow rules for `--`, see #13004 issue

Kubernetes Pod调度原理介绍

最近两周一直没有抽出时间写点Kubernetes的东西,这篇学习一下Kubernetes对Pod的调度。我们先来复习一下Kubernetes的一些基本概念。

Kubernetes的基本概念

Kubernetes是一个基于容器技术的分布式架构平台,它首先是一个开源的容器集群管理系统,又是一个分布式系统开发、运维和支撑平台。 Kubernetes为容器应用提供了服务注册和发现、负载均衡、服务部署和运行、服务滚动升级、在线扩容和缩容、资源调度、资源配额管理等功能。 可以说Kubernetes具备完备的集群管理能力,贯串分布式系统开发、测试、部署、运维监控各个环节。

Kubernetes中的绝大部分概念都抽象成Kubernetes管理的一种资源对象,下面我们一起复习一下这些基本概念:

1、Master:Master节点是Kubernetes集群的控制节点,负责整个集群的管理和控制。Master节点上包含以下组件:

  • kube-apiserver:集群控制的入口,提供HTTP REST服务
  • kube-controller-manager:Kubernetes集群中所有资源对象的自动化控制中心
  • kube-scheduler:负责Pod的调度,我们本篇将主要学一下kube-scheduler的调度功能

2、Node: Node节点是Kubernetes集群中的工作节点,Node上的工作负载由Master节点分配,工作负载主要是运行容器应用。Node节点上包含以下组件:

  • kubelet:负责Pod的创建、启动、监控、重启、销毁等工作,同时与Master节点协作,实现集群管理的基本功能。
  • kube-proxy:实现Kubernetes Service的通信和负载均衡
  • 运行运行容器化(Pod)应用

3、Pod: Pod是Kubernetes最基本的部署调度单元。每个Pod可以由一个或多个业务容器和一个根容器(Pause容器)组成。一个Pod表示某个应用的一个实例

4、ReplicaSet:是Pod副本的抽象,用于解决Pod的扩容和伸缩

5、Deployment:Deployment表示部署,在内部使用ReplicaSet来实现。可以通过Deployment来生成相应的ReplicaSet完成Pod副本的创建

6、Service:Service是Kubernetes最重要的资源对象。Kubernetes中的Service对象可以对应微服务架构中的微服务。Service定义了服务的访问入口,服务的调用者Pod通过这个地址访问Service后端的Pod副本实例。 Service通过Label Selector同后端的Pod副本建立关系,Deployment保证后端Pod副本的数量,也就是保证服务的伸缩性

kube-scheduler调度过程

Master节点上的kube-scheduler负责Pod的调度,kube-scheduler将Pod安置到目标Node上,之后将Pod交给目标Node上的kubelet,Pod生命周期后续的部分由kubelet接管。

kube-scheduler使用特定的调度算法和调度策略将等待调度的Pod调度到某个合适的Node上。等待调度的Pod包含使用API创建的Pod,也包含ControllerManager为补足副本而创建的Pod。具体过程为kube-scheduler会从待调度Pod列表中取出每个Pod,并根据调度算法和调度策略从Node列表中选出一个最合适的Node,将Pod和目标Node绑定(Binding),同时将绑定信息写入到etcd中。目标Node上的kubelet通过kube-apiserver监听到kube-scheduler触发的Pod和目标Node的绑定事件,就会pull镜像和启动容器。

预选(Predicates)和优选(Priorites)步骤

kube-scheduler当前提供的调度过程包含预选(Predicates)和优选(Priorites)两步:

  • 预选(Predicates):将根据配置的预选策略(Predicates Policies)过滤掉不满足这些策略的Node,剩下的Node将作为候选Node成为优选过程的输入。

  • 优选(Priorites):根据配置的优选策略(Priorities Policies)计算出每个候选Node的积分,按积分排名,得分最高的Node胜出,Pod会和该Node绑定。

kube-scheduler进程的–algorithm-provider参数用于指定调度算法,当前Kubernetes版本1.6默认配置的是DefaultProvider。 plugin/pkg/scheduler/algorithmprovider/defaults/defaults.go中包含了默认的Predicates Policies和Priorities Policies。 Scheduler Algorithm in Kubernetes中包含全部的Predicates Policies和Priorities Policies。

另外kube-scheduler可以通过–policy-config-file参数指定想要启用的Predicates Policies和Priorities Policies。例如:

{
"kind" : "Policy",
"apiVersion" : "v1",
"predicates" : [
    {"name" : "PodFitsHostPorts"},
    {"name" : "PodFitsResources"},
    {"name" : "NoDiskConflict"},
    {"name" : "NoVolumeZoneConflict"},
    {"name" : "MatchNodeSelector"},
    {"name" : "HostName"}
    ],
"priorities" : [
    {"name" : "LeastRequestedPriority", "weight" : 1},
    {"name" : "BalancedResourceAllocation", "weight" : 1},
    {"name" : "ServiceSpreadingPriority", "weight" : 1},
    {"name" : "EqualPriority", "weight" : 1}
    ],
"hardPodAffinitySymmetricWeight" : 10
}

Pod调度入门

接下来我们先通过几个例子来学习一下基于预选策略(Predicates Policies)和优选策略(Priorities Policies)实现的Pod调度。 我们可以使用这些策略实现将Pod调度到某个或某些特别的Node上。

我们使用前面在Kubernetes 1.6 高可用集群部署部署的集群作为试验环境。

192.168.61.11 node1
192.168.61.12 node2
192.168.61.13 node3
192.168.61.14 node4

MatchNodeSelector

MatchNodeSelector是一个预选策略,用于判断候选Node是否包含Pod的spec.nodeSelector指定的标签。

我们先来看看当前集群中的Node具有的标签:

kubectl get nodes --show-labels
NAME      STATUS    AGE       VERSION   LABELS
node1     Ready     34d       v1.6.2    beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=node1
node2     Ready     32d       v1.6.2    beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=node2
node3     Ready     32d       v1.6.2    beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=node3
node4     Ready     29d       v1.6.2    beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=node4

可以看到每个Node上都有kubernetes.io/hostname=xxx这个label,我们可以使用Pod的spec.nodeSelector指定这个label将Pod调度具体的某个Node上。例如我们创建一个如下的Deployment,nginx-deployment.yaml:

apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
      nodeSelector:
        kubernetes.io/hostname: node4
kubectl create -f nginx-deployment.yaml
deployment "nginx-deployment" created

kubectl get deploy
NAME               DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   2         2         2            2           1m

kubectl get pod -o wide
NAME                                READY     STATUS        RESTARTS   AGE       IP           NODE
nginx-deployment-1270158812-9qh1v   1/1       Running       0          1m        10.244.3.5   node4
nginx-deployment-1270158812-f5k7h   1/1       Running       0          1m        10.244.3.6   node4

可以看到这个Pod的两个副本都被调度到node4上。下面继续试验,假设我们要将Pod调度到磁盘类型为ssd并且专门用来跑Web应用的Node上。 我们先删除前面创建的Deployment:

kubectl delete deploy nginx-deployment

我们给node1, node2, node3标记如下:

kubectl label node node1 disktype=ssd apptype=web
kubectl label node node2 disktype=ssd
kubectl label node node3 disktype=ssd apptype=web
kubectl label node node4 apptype=web

kubectl get nodes --show-labels
NAME      STATUS    AGE       VERSION   LABELS
node1     Ready     34d       v1.6.2    apptype=web,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/hostname=node1
node2     Ready     32d       v1.6.2    beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/hostname=node2
node3     Ready     32d       v1.6.2    apptype=web,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/hostname=node3
node4     Ready     29d       v1.6.2    apptype=web,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=node4

修改前面的nginx-deployment.yaml文件:

apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
      nodeSelector:
        disktype: ssd
        apptype: web
kubectl create -f nginx-deployment.yaml
deployment "nginx-deployment" created

kubectl get deploy
NAME               DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   2         2         2            0           45s

kubectl get pod -o wide
NAME                               READY     STATUS    RESTARTS   AGE       IP            NODE
nginx-deployment-908661896-pzs2z   1/1       Running   0          2m        10.244.0.69   node1
nginx-deployment-908661896-wvd9p   1/1       Running   0          2m        10.244.2.51   node3

可以看到Pod被调度到了node1和node3上,而node1和node3上我们前面标记了disktype=ssd和apptype=web。

NodeAffinityPriority

NodeAffinityPriority是一个优选策略,是Kubernetes 1.2开始提供的Kubernetes调度中的亲和性机制。NodeAffinityPriority的Node选择器不再限于对Node Label的精确匹配,而支持多种操作符(如In, NotIn, Exists, DoesNotExist, Gt, Lt)。支持两种类型的选择器,一种是requiredDuringSchedulingIgnoredDuringExecution,它保证所选的Node必须满足Pod对Node的所有要求,这种更像前面的MatchNodeSelector;另外一种是preferresDuringSchedulingIgnoredDuringExecution,它对kube-scheduler提出需求,kube-scheduler会尽量但不保证满足NodeSelector的要求。

例如:

apiVersion: v1
kind: Pod
metadata:
  name: with-pod-affinity
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: security
            operator: In
            values:
            - S1
        topologyKey: failure-domain.beta.kubernetes.io/zone
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: security
              operator: In
              values:
              - S2
          topologyKey: kubernetes.io/hostname
  containers:
  - name: with-pod-affinity
    image: gcr.io/google_containers/pause:2.0

解决Kubernetes 1.6.4 Dashboard无法访问的问题

前一段时间将之前采用kubeadm安装的Kubernetes 1.5.1环境升级到了1.6.4版本,升级过程较为顺利。由于该k8s cluster是一个测试环境,当时并没有过于关注,就忙别的事情了。最近项目组打算在这个环境下做一些事情,而当我们重新“捡起”这个环境时,发现Kubernetes Dashboard无法访问了。

Kubernetes的dashboard可以有很多种访问方式,比如:可以通过暴露nodeport的方式(无身份验证,不安全)、可以通过访问apiserver的api服务的方式等。我们的Dashboard通过APIServer进行访问:

https://apiserver_ip:secure_port/ui

正常情况下通过浏览器访问:https://apiserver_ip:secure_port/ui,浏览器会弹出身份验证对话框,待输入正确的用户名和密码后,便可成功进入Dashboard了。但当前,我们得到的结果却是:

User "system:anonymous" cannot proxy services in the namespace "kube-system".

而访问apiserver(https://apiserver_ip:secure_port/)得到的结果如下:

User "system:anonymous" cannot get  at the cluster scope.

一、问题原因分析

k8s 1.6.x版本与1.5.x版本的一个很大不同在于1.6.x版本启用了RBAC的Authorization mode(授权模型),这点在K8s master init的日志中可以得到证实:

# kubeadm init --apiserver-advertise-address xx.xx.xx
... ...
[init] Using Kubernetes version: v1.6.4
[init] Using Authorization mode: RBAC
[preflight] Running pre-flight checks
[preflight] Starting the kubelet service
[certificates] Generated CA certificate and key.
[certificates] Generated API server certificate and key
.... ...
[apiconfig] Created RBAC rules
[addons] Created essential addon: kube-proxy
[addons] Created essential addon: kube-dns

Your Kubernetes master has initialized successfully!
... ...

在《Kubernetes集群的安全配置》一文中我们提到过Kubernetes API server的访问方法:

Authentication(身份验证) -> Authorization(授权)-> Admission Control(入口条件控制)

只不过在Kubernetes 1.5.x及以前的版本中,Authorization的环节都采用了默认的配置,即”AlwaysAllow”,对访问APIServer并不产生什么影响:

# kube-apiserver -h
... ...
--authorization-mode="AlwaysAllow": Ordered list of plug-ins to do authorization on secure port. Comma-delimited list of: AlwaysAllow,AlwaysDeny,ABAC,Webhook,RBAC
... ...

但K8s 1.6.x版本中,–authorization-mode的值发生了变化:

# cat /etc/kubernetes/manifests/kube-apiserver.yaml

spec:
  containers:
  - command:
    - kube-apiserver
    - --allow-privileged=true
    ... ...
    - --basic-auth-file=/etc/kubernetes/basic_auth_file
    - --authorization-mode=RBAC
    ... ...

注:这里我们依旧通过basic auth方式进行apiserver的Authentication,而不是用客户端数字证书校验等其他方式。

显然问题的原因就在于这里RBAC授权方式的使用,让我们无法正常访问Dashboard了。

二、Kubernetes RBAC Authorization简介

RBAC Authorization的基本概念是Role和RoleBinding。Role是一些permission的集合;而RoleBinding则是将Role授权给某些User、某些Group或某些ServiceAccount。K8s官方博客《RBAC Support in Kubernetes》一文的中的配图对此做了很生动的诠释:

从上图中我们可以看到:

Role: pod-reader 拥有Pod的get和list permissions;
RoleBinding: pod-reader 将Role: pod-reader授权给右边的User、Group和ServiceAccount。

和Role和RoleBinding对应的是,K8s还有ClusterRole和ClusterRoleBinding的概念,它们不同之处在于:ClusterRole和ClusterRoleBinding是针对整个Cluster范围内有效的,无论用户或资源所在的namespace是什么;而Role和RoleBinding的作用范围是局限在某个k8s namespace中的。

Kubernetes 1.6.4安装时内建了许多Role/ClusterRole和RoleBinds/ClusterRoleBindings:

# kubectl get role -n kube-system
NAME                                        AGE
extension-apiserver-authentication-reader   50d
system:controller:bootstrap-signer          50d
system:controller:token-cleaner             50d

# kubectl get rolebinding -n kube-system
NAME                                 AGE
system:controller:bootstrap-signer   50d
system:controller:token-cleaner      50d

# kubectl get clusterrole
NAME                                           AGE
admin                                          50d
cluster-admin                                  50d
edit                                           50d
system:auth-delegator                          50d
system:basic-user                              50d
system:controller:attachdetach-controller      50d
... ...
system:discovery                               50d
system:heapster                                50d
system:kube-aggregator                         50d
system:kube-controller-manager                 50d
system:kube-dns                                50d
system:kube-scheduler                          50d
system:node                                    50d
system:node-bootstrapper                       50d
system:node-problem-detector                   50d
system:node-proxier                            50d
system:persistent-volume-provisioner           50d
view                                           50d
weave-net                                      50d

# kubectl get clusterrolebinding
NAME                                           AGE
cluster-admin                                  50d
kubeadm:kubelet-bootstrap                      50d
kubeadm:node-proxier                           50d
kubernetes-dashboard                           50d
system:basic-user                              50d
system:controller:attachdetach-controller      50d
... ...
system:controller:statefulset-controller       50d
system:controller:ttl-controller               50d
system:discovery                               50d
system:kube-controller-manager                 50d
system:kube-dns                                50d
system:kube-scheduler                          50d
system:node                                    50d
system:node-proxier                            50d
weave-net                                      50d

三、Dashboard的role和rolebinding

Kubernetes 1.6.x启用RBAC后,诸多周边插件也都推出了适合K8s 1.6.x的manifest描述文件,比如:weave-net等。Dashboard的manifest文件中也增加了关于rolebinding的描述,我当初用的是1.6.1版本,文件内容摘录如下:

// kubernetes-dashboard.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: kubernetes-dashboard
  labels:
    k8s-app: kubernetes-dashboard
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: kubernetes-dashboard
  namespace: kube-system
... ...

我们看到在kubernetes-dashboard.yaml中,描述文件新建了一个ClusterRoleBinding:kubernetes-dashboard。该binding将ClusterRole: cluster-admin授权给了一个ServiceAccount: kubernetes-dashboard。我们看看ClusterRole: cluster-admin都包含了哪些permission:

# kubectl get clusterrole/cluster-admin -o yaml
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  creationTimestamp: 2017-05-30T14:06:39Z
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: cluster-admin
  resourceVersion: "11"
  selfLink: /apis/rbac.authorization.k8s.io/v1beta1/clusterrolescluster-admin
  uid: 331c79dc-4541-11e7-bc9a-12584ec3a8c9
rules:
- apiGroups:
  - '*'
  resources:
  - '*'
  verbs:
  - '*'
- nonResourceURLs:
  - '*'
  verbs:
  - '*'

可以看到,在rules设定中,cluster-admin似乎拥有了“无限”权限。不过注意:这里仅仅授权给了一个service account,并没有授权给user或group。并且这里的kubernetes-dashboard是dashboard访问apiserver时使用的(下图右侧流程),并不是user访问APIServer时使用的。

我们需要给登录dashboard或者说apiserver的user(图左侧)进行授权。

四、为user: admin进行授权

我们的kube-apiserver的启动参数中包含:

    - --basic-auth-file=/etc/kubernetes/basic_auth_file

也就是说我们访问apiserver使用的是basic auth的身份验证方式,而user恰为admin。而从本文开头的错误现象来看,admin这个user并未得到足够的授权。这里我们要做的就是给admin选择一个合适的clusterrole。但kubectl并不支持查看user的信息,初始的clusterrolebinding又那么多,一一查看十分麻烦。我们知道cluster-admin这个clusterrole是全权限的,我们就来将admin这个user与clusterrole: cluster-admin bind到一起:

# kubectl create clusterrolebinding login-on-dashboard-with-cluster-admin --clusterrole=cluster-admin --user=admin
clusterrolebinding "login-on-dashboard-with-cluster-admin" created

# kubectl get clusterrolebinding/login-on-dashboard-with-cluster-admin -o yaml
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  creationTimestamp: 2017-07-20T08:57:07Z
  name: login-on-dashboard-with-cluster-admin
  resourceVersion: "5363564"
  selfLink: /apis/rbac.authorization.k8s.io/v1beta1/clusterrolebindingslogin-on-dashboard-with-cluster-admin
  uid: 686a3f36-6d29-11e7-8f69-00163e1001d7
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: admin

binding后,我们再来访问一下dashboard UI,不出意外的话,熟悉的dashboard界面就会出现在你的眼前。

用curl测试结果如下:

$curl -u admin:YOUR_PASSWORD -k https://apiserver_ip:secure_port/
{
  "paths": [
    "/api",
    "/api/v1",
    "/apis",
    "/apis/apps",
    "/apis/apps/v1beta1",
    "/apis/authentication.k8s.io",
    "/apis/authentication.k8s.io/v1",
    "/apis/authentication.k8s.io/v1beta1",
    "/apis/authorization.k8s.io",
    "/apis/authorization.k8s.io/v1",
    "/apis/authorization.k8s.io/v1beta1",
    "/apis/autoscaling",
    "/apis/autoscaling/v1",
    "/apis/autoscaling/v2alpha1",
    "/apis/batch",
    "/apis/batch/v1",
    "/apis/batch/v2alpha1",
    "/apis/certificates.k8s.io",
    "/apis/certificates.k8s.io/v1beta1",
    "/apis/extensions",
    "/apis/extensions/v1beta1",
    "/apis/policy",
    "/apis/policy/v1beta1",
    "/apis/rbac.authorization.k8s.io",
    "/apis/rbac.authorization.k8s.io/v1alpha1",
    "/apis/rbac.authorization.k8s.io/v1beta1",
    "/apis/settings.k8s.io",
    "/apis/settings.k8s.io/v1alpha1",
    "/apis/storage.k8s.io",
    "/apis/storage.k8s.io/v1",
    "/apis/storage.k8s.io/v1beta1",
    "/healthz",
    "/healthz/ping",
    "/healthz/poststarthook/bootstrap-controller",
    "/healthz/poststarthook/ca-registration",
    "/healthz/poststarthook/extensions/third-party-resources",
    "/healthz/poststarthook/rbac/bootstrap-roles",
    "/logs",
    "/metrics",
    "/swaggerapi/",
    "/ui/",
    "/version"
  ]
}

k8s(kubernetes)安全控制认证与授权

kubernetes 对于访问 API 来说提供了两个步骤的安全措施:认证和授权。认证解决用户是谁的问题,授权解决用户能做什么的问题。通过合理的权限管理,能够保证系统的安全可靠。

通俗的讲,认证就是验证用户名密码,授权就是检查该用户是否拥有权限访问请求的资源。

Kubernetes集群的所有操作基本上都是通过kube-apiserver这个组件进行的,它提供HTTP RESTful形式的API供集群内外客户端调用。需要注意的是:认证授权过程只存在HTTPS形式的API中。也就是说,如果客户端使用HTTP连接到kube-apiserver,那么是不会进行认证授权的。所以说,可以这么设置,在集群内部组件间通信使用HTTP,集群外部就使用HTTPS,这样既增加了安全性,也不至于太复杂。

下图是 API 访问要经过的三个步骤,前面两个是认证和授权,第三个是 Admission Control,它也能在一定程度上提高安全性,不过更多是资源管理方面的作用。

未分类

下面将介绍1.6版本中已经支持的一些认证方式。

客户端证书

客户端证书认证叫作TLS双向认证,也就是服务器客户端互相验证证书的正确性,在都正确的情况下协调通信加密方案。

为了使用这个方案,api-server需要用-client-ca-file=选项来开启。CA_CERTIFICATE_FILE肯定包括一个或者多个认证中心,可以被用来验证呈现给api-server的客户端证书。客户端证书的/CN将作为用户名。

静态Token文件

用token唯一标识请求者,只要apiserver存在该token,则认为认证通过,但是如果需要新增Token,则需要重启kube-apiserver组件,实际效果不是很好。

当在命令行指定- -token-auth-file=SOMEFILE选项时,API服务器从文件中读取 bearer tokens。目前,tokens持续无限期。

令牌文件是一个至少包含3列的csv文件: token, user name, user uid,后跟可选的组名。注意,如果您有多个组,则列必须是双引号,例如:

token,user,uid,"group1,group2,group3"

当通过客户端使用 bearer token 认证时,API服务器需要一个值为Bearer THETOKEN的授权头。bearer token必须是,可以放在HTTP请求头中且值不需要转码和引用的一个字符串。例如:如果bearer token是31ada4fd-adec-460c-809a-9e56ceb75269,它将会在HTTP头中按下面的方式呈现:

Authorization: Bearer 31ada4fd-adec-460c-809a-9e56ceb75269

引导Token

在v1.6版本中,这个特性还是alpha特性。为了能够在新的集群中使用bootstrapping认证。Kubernetes包括一种动态管理的Bearer(持票人) token,这种token以Secrets的方式存储在kube-system命名空间中,在这个命名空间token可以被动态的管理和创建。Controller Manager有一个管理中心,如果token过期了就会删除。

创建的token证书满足[a-z0-9]{6}.[a-z0-9]{16}格式,Token的第一部分是一个Token ID,第二部分是token的秘钥。你需要在http协议头中加上类似的信息:

Authorization: Bearer 781292.db7bc3a58fc5f07e

如果要使用Bootstrap,需要在API Sever中开启–experimental-bootstrap-token-auth。同时必须在Controller Manager中开启管理中心的设置–controllers=*,tokencleaner。

在使用kubeadm部署Kubernetes时,kubeadm会自动创建默认token,可通过kubeadm token list命令查询。

静态密码文件

静态密码的方式是提前在某个文件中保存了用户名和密码的信息,然后在 apiserver 启动的时候通过参数 –basic-auth-file=SOMEFILE 指定文件的路径。apiserver 一旦启动,加载的用户名和密码信息就不会发生改变,任何对源文件的修改必须重启 apiserver 才能生效。

静态密码文件是 CSV 格式的文件,每行对应一个用户的信息,前面三列密码、用户名、用户 ID 是必须的,第四列是可选的组名(如果有多个组,必须用双引号):

password,user,uid,"group1,group2,group3"

客户端在发送请求的时候需要在请求头部添加上 Authorization 字段,对应的值是 Basic BASE64ENCODED(USER:PASSWORD) 。apiserver 解析出客户端提供的用户名和密码,如果和文件中的某一行匹配,就认为认证成功。

注意:

这种方式很不灵活,也不安全,可以说名存实亡,不推荐使用。

Service Account Tokens 认证

有些情况下,我们希望在 pod 内部访问 apiserver,获取集群的信息,甚至对集群进行改动。针对这种情况,kubernetes 提供了一种特殊的认证方式:Service Account。 Service Account 是面向 namespace 的,每个 namespace 创建的时候,kubernetes 会自动在这个 namespace 下面创建一个默认的 Service Account;并且这个 Service Account 只能访问该 namespace 的资源。Service Account 和 pod、service、deployment 一样是 kubernetes 集群中的一种资源,用户也可以创建自己的 serviceaccount。

ServiceAccount 主要包含了三个内容:namespace、Token 和 CA。namespace 指定了 pod 所在的 namespace,CA 用于验证 apiserver 的证书,token 用作身份验证。它们都通过 mount 的方式保存在 pod 的文件系统中,其中 token 保存的路径是 /var/run/secrets/kubernetes.io/serviceaccount/token ,是 apiserver 通过私钥签发 token 的 base64 编码后的结果; CA 保存的路径是 /var/run/secrets/kubernetes.io/serviceaccount/ca.crt ,namespace 保存的路径是 /var/run/secrets/kubernetes.io/serviceaccount/namespace ,也是用 base64 编码。

如果 token 能够通过认证,那么请求的用户名将被设置为 system:serviceaccount:(NAMESPACE):(SERVICEACCOUNT) ,而请求的组名有两个: system:serviceaccounts 和 system:serviceaccounts:(NAMESPACE)。

关于 Service Account 的配置可以参考官方的 Manager Service Accounts 文档。

OpenID Connect Tokens 认证

OpenID Connect 是一些由OAuth2提供商支持的OAuth2,特别是Azure Active Directory,Salesforce和Google。OAuth2的协议的主要扩展是增加一个额外字段,返回了一个叫ID token的access token。这个token是被服务器签名的JSON Web Token (JWT) ,具有众所周知的字段,比如用户的email。

为了识别用户,验证使用来自OAuth2 token响应的id_token (而不是 access_token)作为bearer token。token如何包含在请求中可以参考下图:

未分类

使用OpenID认证,API Server需要配置
– –oidc-issuer-url,如https://accounts.google.com
– –oidc-client-id,如kubernetes
– –oidc-username-claim,如sub
– –oidc-groups-claim,如groups
– –oidc-ca-file,如/etc/kubernetes/ssl/kc-ca.pem

Webhook Token 认证

Webhook Token 认证方式可以让用户使用自己的认证方式,用户只需要按照约定的请求格式和应答格式提供 HTTPS 服务,当用户把 Bearer Token 放到请求的头部,kubernetes 会把 token 发送给事先配置的地址进行认证,如果认证结果成功,则认为请求用户合法。 这种方式下有两个参数可以配置:

–authentication-token-webhook-config-file :kubeconfig 文件说明如果访问认证服务器

–authentication-token-webhook-cache-ttl :认证结果要缓存多久,默认是两分钟
这种方式下,自定义认证的请求和应答都有一定的格式,具体的规范请参考 官方文档的说明 。

认证代理

API Server需要配置

–requestheader-username-headers=X-Remote-User
–requestheader-group-headers=X-Remote-Group
–requestheader-extra-headers-prefix=X-Remote-Extra-
#为了防止头部欺骗,证书是必选项
–requestheader-client-ca-file
#设置允许的CN列表。可选。
–requestheader-allowed-names

Keystone Password 认证

Keystone 是 OpenStack 提供的认证和授权组件,这个方法对于已经使用 openstack 来搭建 Iaas 平台的公司比较适用,直接使用 keystone 可以保证 Iaas 和 Caas 平台保持一致的用户体系。

需要API Server在启动时指定–experimental-keystone-url=,而https时还需要设置–experimental-keystone-ca-file=SOMEFILE。

匿名请求

如果请求没有通过以上任何方式的认证,正常情况下应该是直接返回 401 错误。但是 kubernetes 还提供另外一种选择,给没有通过认证的请求一个特殊的用户名 system:anonymous 和组名 system:unauthenticated 。

这样的话,可以跟下面要讲的授权结合起来,为匿名请求设置一些特殊的权限,比如只能读取当前 namespace 的 pod 信息,方便用户访问。

如果使用AlwaysAllow以外的认证模式,则匿名请求默认开启,但可用–anonymous-auth=false禁止匿名请求。

手动一步步搭建k8s(Kubernetes)高可用集群

以前一直用 Kargo(基于 ansible) 来搭建 Kubernetes 集群,最近发现 ansible 部署的时候有些东西有点 bug,而且 Kargo 对 rkt 等也做了适配,感觉问题已经有点复杂化了;在 2.2 release 没出来这个时候,准备自己纯手动挡部署一下,Master HA 直接抄 Kargo 的就行了,以下记录一下

一、环境准备

以下文章本着 多写代码少哔哔 的原则,会主要以实际操作为主,不会过多介绍每步细节动作,如果纯小白想要更详细的了解,可以参考 这里

环境总共 5 台虚拟机,2 个 master,3 个 etcd 节点,master 同时也作为 node 负载 pod,在分发证书等阶段将在另外一台主机上执行,该主机对集群内所有节点配置了 ssh 秘钥登录

未分类

网络方案这里采用性能比较好的 Calico,集群开启 RBAC,RBAC 相关可参考:https://mritd.me/2017/07/17/kubernetes-rbac-chinese-translation/

二、证书相关处理

2.1、证书说明

由于 Etcd 和 Kubernetes 全部采用 TLS 通讯,所以先要生成 TLS 证书,证书生成工具采用 cfssl,具体使用方法这里不再详细阐述,生成证书时可在任一节点完成,这里在宿主机执行,证书列表如下

未分类

2.2、CFSSL 工具安装

首先下载 cfssl,并给予可执行权限,然后扔到 PATH 目录下

wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
chmod +x cfssl_linux-amd64 cfssljson_linux-amd64
mv cfssl_linux-amd64 /usr/local/bin/cfssl
mv cfssljson_linux-amd64 /usr/local/bin/cfssljson

2.3、生成 Etcd 证书

Etcd 证书生成所需配置文件如下:

  • etcd-root-ca-csr.json
{
  "key": {
    "algo": "rsa",
    "size": 4096
  },
  "names": [
    {
      "O": "etcd",
      "OU": "etcd Security",
      "L": "Beijing",
      "ST": "Beijing",
      "C": "CN"
    }
  ],
  "CN": "etcd-root-ca"
}
  • etcd-gencert.json
{
  "signing": {
    "default": {
        "usages": [
          "signing",
          "key encipherment",
          "server auth",
          "client auth"
        ],
        "expiry": "87600h"
    }
  }
}
  • etcd-csr.json
{
  "key": {
    "algo": "rsa",
    "size": 4096
  },
  "names": [
    {
      "O": "etcd",
      "OU": "etcd Security",
      "L": "Beijing",
      "ST": "Beijing",
      "C": "CN"
    }
  ],
  "CN": "etcd",
  "hosts": [
    "127.0.0.1",
    "localhost",
    "192.168.1.11",
    "192.168.1.12",
    "192.168.1.13",
    "192.168.1.14",
    "192.168.1.15"
  ]
}

最后生成 Etcd 证书

cfssl gencert --initca=true etcd-root-ca-csr.json | cfssljson --bare etcd-root-ca
cfssl gencert --ca etcd-root-ca.pem --ca-key etcd-root-ca-key.pem --config etcd-gencert.json etcd-csr.json | cfssljson --bare etcd

生成的证书列表如下

未分类

2.4、生成 Kubernetes 证书

Kubernetes 证书生成所需配置文件如下:

  • k8s-root-ca-csr.json
{
  "CN": "kubernetes",
  "key": {
    "algo": "rsa",
    "size": 4096
  },
  "names": [
    {
      "C": "CN",
      "ST": "BeiJing",
      "L": "BeiJing",
      "O": "k8s",
      "OU": "System"
    }
  ]
}
  • k8s-gencert.json
{
  "signing": {
    "default": {
      "expiry": "87600h"
    },
    "profiles": {
      "kubernetes": {
        "usages": [
            "signing",
            "key encipherment",
            "server auth",
            "client auth"
        ],
        "expiry": "87600h"
      }
    }
  }
}
  • kubernetes-csr.json
{
    "CN": "kubernetes",
    "hosts": [
        "127.0.0.1",
        "10.254.0.1",
        "192.168.1.11",
        "192.168.1.12",
        "192.168.1.13",
        "192.168.1.14",
        "192.168.1.15",
        "localhost",
        "kubernetes",
        "kubernetes.default",
        "kubernetes.default.svc",
        "kubernetes.default.svc.cluster",
        "kubernetes.default.svc.cluster.local"
    ],
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "ST": "BeiJing",
            "L": "BeiJing",
            "O": "k8s",
            "OU": "System"
        }
    ]
}
  • kube-proxy-csr.json
{
  "CN": "system:kube-proxy",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "BeiJing",
      "L": "BeiJing",
      "O": "k8s",
      "OU": "System"
    }
  ]
}
  • admin-csr.json
{
  "CN": "admin",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "BeiJing",
      "L": "BeiJing",
      "O": "system:masters",
      "OU": "System"
    }
  ]
}

生成 Kubernetes 证书

cfssl gencert --initca=true k8s-root-ca-csr.json | cfssljson --bare k8s-root-ca

for targetName in kubernetes admin kube-proxy; do
    cfssl gencert --ca k8s-root-ca.pem --ca-key k8s-root-ca-key.pem --config k8s-gencert.json --profile kubernetes $targetName-csr.json | cfssljson --bare $targetName
done

生成后证书列表如下

未分类

2.5、生成 token 及 kubeconfig

生成 token 如下

export BOOTSTRAP_TOKEN=$(head -c 16 /dev/urandom | od -An -t x | tr -d ' ')
cat > token.csv <<EOF
${BOOTSTRAP_TOKEN},kubelet-bootstrap,10001,"system:kubelet-bootstrap"
EOF

创建 kubelet bootstrapping kubeconfig 配置,对于 node 节点,api server 地址为本地 nginx 监听的 127.0.0.1:6443,如果想把 master 也当做 node 使用,那么 master 上 api server 地址应该为 masterIP:6443,因为在 master 上没必要也无法启动 nginx 来监听 127.0.0.1:6443(6443 已经被 master 上的 api server 占用了)

所以以下配置只适合 node 节点,如果想把 master 也当做 node,那么需要重新生成下面的 kubeconfig 配置,并把 api server 地址修改为当前 master 的 api server 地址

export KUBE_APISERVER="https://127.0.0.1:6443"
# 设置集群参数
kubectl config set-cluster kubernetes 
  --certificate-authority=k8s-root-ca.pem 
  --embed-certs=true 
  --server=${KUBE_APISERVER} 
  --kubeconfig=bootstrap.kubeconfig
# 设置客户端认证参数
kubectl config set-credentials kubelet-bootstrap 
  --token=${BOOTSTRAP_TOKEN} 
  --kubeconfig=bootstrap.kubeconfig
# 设置上下文参数
kubectl config set-context default 
  --cluster=kubernetes 
  --user=kubelet-bootstrap 
  --kubeconfig=bootstrap.kubeconfig
# 设置默认上下文
kubectl config use-context default --kubeconfig=bootstrap.kubeconfig

创建 kube-proxy kubeconfig 配置,同上面一样,如果想要把 master 当 node 使用,需要修改 api server

# 设置集群参数
kubectl config set-cluster kubernetes 
  --certificate-authority=k8s-root-ca.pem 
  --embed-certs=true 
  --server=${KUBE_APISERVER} 
  --kubeconfig=kube-proxy.kubeconfig
# 设置客户端认证参数
kubectl config set-credentials kube-proxy 
  --client-certificate=kube-proxy.pem 
  --client-key=kube-proxy-key.pem 
  --embed-certs=true 
  --kubeconfig=kube-proxy.kubeconfig
# 设置上下文参数
kubectl config set-context default 
  --cluster=kubernetes 
  --user=kube-proxy 
  --kubeconfig=kube-proxy.kubeconfig
# 设置默认上下文
kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig

三、部署 HA ETCD

3.1、安装 Etcd

ETCD 直接采用 rpm 安装,RPM 可以从 Fedora 官方仓库 获取 spec 文件自己 build,或者直接从 rpmFind 网站 搜索

# 下载 rpm 包
wget ftp://195.220.108.108/linux/fedora/linux/development/rawhide/Everything/x86_64/os/Packages/e/etcd-3.1.9-1.fc27.x86_64.rpm
# 分发并安装 rpm
for IP in `seq 1 3`; do
    scp etcd-3.1.9-1.fc27.x86_64.rpm [email protected]$IP:~
    ssh [email protected]$IP rpm -ivh etcd-3.1.9-1.fc27.x86_64.rpm
done

3.2、分发证书

for IP in `seq 1 3`;do
    ssh [email protected]$IP mkdir /etc/etcd/ssl
    scp *.pem [email protected]$IP:/etc/etcd/ssl
    ssh [email protected]$IP chown -R etcd:etcd /etc/etcd/ssl
    ssh [email protected]$IP chmod -R 755 /etc/etcd
done

3.3、修改配置

rpm 安装好以后直接修改 /etc/etcd/etcd.conf 配置文件即可,其中单个节点配置如下(其他节点只是名字和 IP 不同)

# [member]
ETCD_NAME=etcd1
ETCD_DATA_DIR="/var/lib/etcd/etcd1.etcd"
ETCD_WAL_DIR="/var/lib/etcd/wal"
ETCD_SNAPSHOT_COUNT="100"
ETCD_HEARTBEAT_INTERVAL="100"
ETCD_ELECTION_TIMEOUT="1000"
ETCD_LISTEN_PEER_URLS="https://192.168.1.11:2380"
ETCD_LISTEN_CLIENT_URLS="https://192.168.1.11:2379,http://127.0.0.1:2379"
ETCD_MAX_SNAPSHOTS="5"
ETCD_MAX_WALS="5"
#ETCD_CORS=""

# [cluster]
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://192.168.1.11:2380"
# if you use different ETCD_NAME (e.g. test), set ETCD_INITIAL_CLUSTER value for this name, i.e. "test=http://..."
ETCD_INITIAL_CLUSTER="etcd1=https://192.168.1.11:2380,etcd2=https://192.168.1.12:2380,etcd3=https://192.168.1.13:2380"
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_ADVERTISE_CLIENT_URLS="https://192.168.1.11:2379"
#ETCD_DISCOVERY=""
#ETCD_DISCOVERY_SRV=""
#ETCD_DISCOVERY_FALLBACK="proxy"
#ETCD_DISCOVERY_PROXY=""
#ETCD_STRICT_RECONFIG_CHECK="false"
#ETCD_AUTO_COMPACTION_RETENTION="0"

# [proxy]
#ETCD_PROXY="off"
#ETCD_PROXY_FAILURE_WAIT="5000"
#ETCD_PROXY_REFRESH_INTERVAL="30000"
#ETCD_PROXY_DIAL_TIMEOUT="1000"
#ETCD_PROXY_WRITE_TIMEOUT="5000"
#ETCD_PROXY_READ_TIMEOUT="0"

# [security]
ETCD_CERT_FILE="/etc/etcd/ssl/etcd.pem"
ETCD_KEY_FILE="/etc/etcd/ssl/etcd-key.pem"
ETCD_CLIENT_CERT_AUTH="true"
ETCD_TRUSTED_CA_FILE="/etc/etcd/ssl/etcd-root-ca.pem"
ETCD_AUTO_TLS="true"
ETCD_PEER_CERT_FILE="/etc/etcd/ssl/etcd.pem"
ETCD_PEER_KEY_FILE="/etc/etcd/ssl/etcd-key.pem"
ETCD_PEER_CLIENT_CERT_AUTH="true"
ETCD_PEER_TRUSTED_CA_FILE="/etc/etcd/ssl/etcd-root-ca.pem"
ETCD_PEER_AUTO_TLS="true"

# [logging]
#ETCD_DEBUG="false"
# examples for -log-package-levels etcdserver=WARNING,security=DEBUG
#ETCD_LOG_PACKAGE_LEVELS=""

3.4、启动及验证

配置修改后在每个节点进行启动即可,注意,Etcd 哥哥节点间必须保证时钟同步,否则会造成启动失败等错误

systemctl daemon-reload
systemctl start etcd
systemctl enable etcd

启动成功后验证节点状态

export ETCDCTL_API=3
etcdctl --cacert=/etc/etcd/ssl/etcd-root-ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem --endpoints=https://192.168.1.11:2379,https://192.168.1.12:2379,https://192.168.1.13:2379 endpoint health

最后截图如下,警告可忽略

未分类

四、部署 HA Master

4.1、HA Master 简述

目前所谓的 Kubernetes HA 其实主要的就是 API Server 的 HA,master 上其他组件比如 controller-manager 等都是可以通过 Etcd 做选举;而 API Server 只是提供一个请求接收服务,所以对于 API Server 一般有两种方式做 HA;一种是对多个 API Server 做 vip,另一种使用 nginx 反向代理,本文采用 nginx 方式,以下为 HA 示意图

未分类

master 之间除 api server 以外其他组件通过 etcd 选举,api server 默认不作处理;在每个 node 上启动一个 nginx,每个 nginx 反向代理所有 api server,node 上 kubelet、kube-proxy 连接本地的 nginx 代理端口,当 nginx 发现无法连接后端时会自动踢掉出问题的 api server,从而实现 api server 的 HA

4.2、部署前预处理

一切以偷懒为主,所以我们仍然采用 rpm 的方式来安装 kubernetes 各个组件,关于 rpm 获取方式可以参考 How to build Kubernetes RPM,以下文章默认认为你已经搞定了 rpm

# 分发 rpm
for IP in `seq 1 3`; do
    scp kubernetes*.rpm [email protected]$IP:~; 
    ssh [email protected]$IP yum install -y conntrack-tools socat
    ssh [email protected]$IP rpm -ivh kubernetes*.rpm
done

rpm 安装好以后还需要进行分发证书配置等

for IP in `seq 1 3`;do
    ssh [email protected]$IP mkdir /etc/kubernetes/ssl
    scp *.pem [email protected]$IP:/etc/kubernetes/ssl
    scp *.kubeconfig [email protected]$IP:/etc/kubernetes
    scp token.csv [email protected]$IP:/etc/kubernetes
    ssh [email protected]$IP chown -R kube:kube /etc/kubernetes/ssl
done

最后由于 api server 会写入一些日志,所以先创建好相关目录,并做好授权,防止因为权限错误导致 api server 无法启动

for IP in `seq 1 3`;do
    ssh [email protected]$IP mkdir /var/log/kube-audit  
    ssh [email protected]$IP chown -R kube:kube /var/log/kube-audit
    ssh [email protected]$IP chmod -R 755 /var/log/kube-audit
done

4.3、修改 master 配置

rpm 安装好以后,默认会生成 /etc/kubernetes 目录,并且该目录中会有很多配置,其中 config 配置文件为通用配置,具体文件如下

➜  kubernetes tree
.
├── apiserver
├── config
├── controller-manager
├── kubelet
├── proxy
└── scheduler

0 directories, 6 files

master 需要编辑 config、apiserver、controller-manager、scheduler这四个文件,具体修改如下

  • config 通用配置
###
# kubernetes system config
#
# The following values are used to configure various aspects of all
# kubernetes services, including
#
#   kube-apiserver.service
#   kube-controller-manager.service
#   kube-scheduler.service
#   kubelet.service
#   kube-proxy.service
# logging to stderr means we get it in the systemd journal
KUBE_LOGTOSTDERR="--logtostderr=true"

# journal message level, 0 is debug
KUBE_LOG_LEVEL="--v=2"

# Should this cluster be allowed to run privileged docker containers
KUBE_ALLOW_PRIV="--allow-privileged=true"

# How the controller-manager, scheduler, and proxy find the apiserver
KUBE_MASTER="--master=http://127.0.0.1:8080"
  • apiserver 配置(其他节点只有 IP 不同)
###
# kubernetes system config
#
# The following values are used to configure the kube-apiserver
#

# The address on the local server to listen to.
KUBE_API_ADDRESS="--advertise-address=192.168.1.11 --insecure-bind-address=127.0.0.1 --bind-address=192.168.1.11"

# The port on the local server to listen on.
KUBE_API_PORT="--insecure-port=8080 --secure-port=6443"

# Port minions listen on
# KUBELET_PORT="--kubelet-port=10250"

# Comma separated list of nodes in the etcd cluster
KUBE_ETCD_SERVERS="--etcd-servers=https://192.168.1.11:2379,https://192.168.1.12:2379,https://192.168.1.13:2379"

# Address range to use for services
KUBE_SERVICE_ADDRESSES="--service-cluster-ip-range=10.254.0.0/16"

# default admission control policies
KUBE_ADMISSION_CONTROL="--admission-control=NamespaceLifecycle,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota"

# Add your own!
KUBE_API_ARGS="--authorization-mode=RBAC 
               --runtime-config=rbac.authorization.k8s.io/v1beta1 
               --anonymous-auth=false 
               --kubelet-https=true 
               --experimental-bootstrap-token-auth 
               --token-auth-file=/etc/kubernetes/token.csv 
               --service-node-port-range=30000-50000 
               --tls-cert-file=/etc/kubernetes/ssl/kubernetes.pem 
               --tls-private-key-file=/etc/kubernetes/ssl/kubernetes-key.pem 
               --client-ca-file=/etc/kubernetes/ssl/k8s-root-ca.pem 
               --service-account-key-file=/etc/kubernetes/ssl/k8s-root-ca.pem 
               --etcd-quorum-read=true 
               --storage-backend=etcd3 
               --etcd-cafile=/etc/etcd/ssl/etcd-root-ca.pem 
               --etcd-certfile=/etc/etcd/ssl/etcd.pem 
               --etcd-keyfile=/etc/etcd/ssl/etcd-key.pem 
               --enable-swagger-ui=true 
               --apiserver-count=3 
               --audit-log-maxage=30 
               --audit-log-maxbackup=3 
               --audit-log-maxsize=100 
               --audit-log-path=/var/log/kube-audit/audit.log 
               --event-ttl=1h"
  • controller-manager 配置
###
# The following values are used to configure the kubernetes controller-manager

# defaults from config and apiserver should be adequate

# Add your own!
KUBE_CONTROLLER_MANAGER_ARGS="--address=0.0.0.0 
                              --service-cluster-ip-range=10.254.0.0/16 
                              --cluster-name=kubernetes 
                              --cluster-signing-cert-file=/etc/kubernetes/ssl/k8s-root-ca.pem 
                              --cluster-signing-key-file=/etc/kubernetes/ssl/k8s-root-ca-key.pem 
                              --service-account-private-key-file=/etc/kubernetes/ssl/k8s-root-ca-key.pem 
                              --root-ca-file=/etc/kubernetes/ssl/k8s-root-ca.pem 
                              --leader-elect=true 
                              --node-monitor-grace-period=40s 
                              --node-monitor-period=5s 
                              --pod-eviction-timeout=5m0s"
  • scheduler 配置
###
# kubernetes scheduler config

# default config should be adequate

# Add your own!
KUBE_SCHEDULER_ARGS="--leader-elect=true --address=0.0.0.0"

其他 master 节点配置相同,只需要修改以下 IP 地址即可,修改完成后启动 api server

systemctl daemon-reload
systemctl start kube-apiserver
systemctl start kube-controller-manager
systemctl start kube-scheduler
systemctl enable kube-apiserver
systemctl enable kube-controller-manager
systemctl enable kube-scheduler

各个节点启动成功后,验证组件状态(kubectl 在不做任何配置的情况下默认链接本地 8080 端口)如下,其中 etcd 全部为 Unhealthy 状态,并且提示 remote error: tls: bad certificate 这是个 bug,不影响实际使用,具体可参考 issue

未分类

五、部署 Node

5.1、部署前预处理

部署前分发 rpm 以及证书、token 等配置

# 分发 rpm
for IP in `seq 4 5`;do
    scp kubernetes-node-1.6.7-1.el7.centos.x86_64.rpm kubernetes-client-1.6.7-1.el7.centos.x86_64.rpm [email protected]$IP:~; 
    ssh [email protected]$IP yum install -y conntrack-tools socat
    ssh [email protected]$IP rpm -ivh kubernetes-node-1.6.7-1.el7.centos.x86_64.rpm kubernetes-client-1.6.7-1.el7.centos.x86_64.rpm
done
# 分发证书等配置文件
for IP in `seq 4 5`;do
    ssh [email protected]$IP mkdir /etc/kubernetes/ssl
    scp *.pem [email protected]$IP:/etc/kubernetes/ssl
    scp *.kubeconfig [email protected]$IP:/etc/kubernetes
    scp token.csv [email protected]$IP:/etc/kubernetes
    ssh [email protected]$IP chown -R kube:kube /etc/kubernetes/ssl
done

5.2、修改 node 配置

node 节点上配置文件同样位于 /etc/kubernetes 目录,node 节点只需要修改 config、kubelet、proxy 这三个配置文件,修改如下

  • config 通用配置

注意: config 配置文件(包括下面的 kubelet、proxy)中全部未 定义 API Server 地址,因为 kubelet 和 kube-proxy 组件启动时使用了 –require-kubeconfig 选项,该选项会使其从 *.kubeconfig 中读取 API Server 地址,而忽略配置文件中设置的;所以配置文件中设置的地址其实是无效的

###
# kubernetes system config
#
# The following values are used to configure various aspects of all
# kubernetes services, including
#
#   kube-apiserver.service
#   kube-controller-manager.service
#   kube-scheduler.service
#   kubelet.service
#   kube-proxy.service
# logging to stderr means we get it in the systemd journal
KUBE_LOGTOSTDERR="--logtostderr=true"

# journal message level, 0 is debug
KUBE_LOG_LEVEL="--v=2"

# Should this cluster be allowed to run privileged docker containers
KUBE_ALLOW_PRIV="--allow-privileged=true"

# How the controller-manager, scheduler, and proxy find the apiserver
# KUBE_MASTER="--master=http://127.0.0.1:8080"

kubelet 配置

###
# kubernetes kubelet (minion) config

# The address for the info server to serve on (set to 0.0.0.0 or "" for all interfaces)
KUBELET_ADDRESS="--address=192.168.1.14"

# The port for the info server to serve on
# KUBELET_PORT="--port=10250"

# You may leave this blank to use the actual hostname
KUBELET_HOSTNAME="--hostname-override=docker4.node"

# location of the api-server
# KUBELET_API_SERVER=""

# Add your own!
KUBELET_ARGS="--cgroup-driver=cgroupfs 
              --cluster-dns=10.254.0.2 
              --resolv-conf=/etc/resolv.conf 
              --experimental-bootstrap-kubeconfig=/etc/kubernetes/bootstrap.kubeconfig 
              --kubeconfig=/etc/kubernetes/kubelet.kubeconfig 
              --require-kubeconfig 
              --cert-dir=/etc/kubernetes/ssl 
              --cluster-domain=cluster.local. 
              --hairpin-mode promiscuous-bridge 
              --serialize-image-pulls=false 
              --pod-infra-container-image=gcr.io/google_containers/pause-amd64:3.0"

proxy 配置

###
# kubernetes proxy config

# default config should be adequate

# Add your own!
KUBE_PROXY_ARGS="--bind-address=192.168.1.14 
                 --hostname-override=docker4.node 
                 --kubeconfig=/etc/kubernetes/kube-proxy.kubeconfig 
                 --cluster-cidr=10.254.0.0/16"

5.3、创建 ClusterRoleBinding

由于 kubelet 采用了 TLS Bootstrapping,所有根绝 RBAC 控制策略,kubelet 使用的用户 kubelet-bootstrap 是不具备任何访问 API 权限的,这是需要预先在集群内创建 ClusterRoleBinding 授予其 system:node-bootstrapper Role

# 在任意 master 执行即可
kubectl create clusterrolebinding kubelet-bootstrap 
  --clusterrole=system:node-bootstrapper 
  --user=kubelet-bootstrap

5.4、创建 nginx 代理

根据上面描述的 master HA 架构,此时所有 node 应该连接本地的 nginx 代理,然后 nginx 来负载所有 api server;以下为 nginx 代理相关配置

# 创建配置目录
mkdir -p /etc/nginx

# 写入代理配置
cat << EOF >> /etc/nginx/nginx.conf
error_log stderr notice;

worker_processes auto;
events {
  multi_accept on;
  use epoll;
  worker_connections 1024;
}

stream {
    upstream kube_apiserver {
        least_conn;
        server 192.168.1.11:6443;
        server 192.168.1.12:6443;
        server 192.168.1.13:6443;
    }

    server {
        listen        0.0.0.0:6443;
        proxy_pass    kube_apiserver;
        proxy_timeout 10m;
        proxy_connect_timeout 1s;
    }
}
EOF

# 更新权限
chmod +r /etc/nginx/nginx.conf

为了保证 nginx 的可靠性,综合便捷性考虑,node 节点上的 nginx 使用 docker 启动,同时 使用 systemd 来守护, systemd 配置如下

cat << EOF >> /etc/systemd/system/nginx-proxy.service
[Unit]
Description=kubernetes apiserver docker wrapper
Wants=docker.socket
After=docker.service

[Service]
User=root
PermissionsStartOnly=true
ExecStart=/usr/bin/docker run -p 127.0.0.1:6443:6443 \
                              -v /etc/nginx:/etc/nginx \
                              --name nginx-proxy \
                              --net=host \
                              --restart=on-failure:5 \
                              --memory=512M \
                              nginx:1.13.3-alpine
ExecStartPre=-/usr/bin/docker rm -f nginx-proxy
ExecStop=/usr/bin/docker stop nginx-proxy
Restart=always
RestartSec=15s
TimeoutStartSec=30s

[Install]
WantedBy=multi-user.target
EOF

最后启动 nginx,同时可以使用 kubectl 测试 api server 负载情况

systemctl daemon-reload
systemctl start nginx-proxy
systemctl enable nginx-proxy

启动成功后如下

未分类

kubectl 测试联通性如下

未分类

5.5、添加 Node

一起准备就绪以后就可以启动 node 相关组件了

systemctl daemon-reload
systemctl start kubelet
systemctl enable kubelet

由于采用了 TLS Bootstrapping,所以 kubelet 启动后不会立即加入集群,而是进行证书申请,从日志中可以看到如下输出

Jul 19 14:15:31 docker4.node kubelet[18213]: I0719 14:15:31.810914   18213 feature_gate.go:144] feature gates: map[]
Jul 19 14:15:31 docker4.node kubelet[18213]: I0719 14:15:31.811025   18213 bootstrap.go:58] Using bootstrap kubeconfig to generate TLS client cert, key and kubeconfig file

此时只需要在 master 允许其证书申请即可

# 查看 csr
➜  kubernetes kubectl get csr
NAME        AGE       REQUESTOR           CONDITION
csr-l9d25   2m        kubelet-bootstrap   Pending
# 签发证书
➜  kubernetes kubectl certificate approve csr-l9d25
certificatesigningrequest "csr-l9d25" approved
# 查看 node
➜  kubernetes kubectl get node
NAME           STATUS    AGE       VERSION
docker4.node   Ready     26s       v1.6.7

最后再启动 kube-proxy 组件即可

systemctl start kube-proxy
systemctl enable kube-proxy

5.6、Master 开启 Pod 负载

Master 上部署 Node 与单独 Node 部署大致相同,只需要修改 bootstrap.kubeconfig、kube-proxy.kubeconfig 中的 API Server 地址即可

未分类

然后修改 kubelet、proxy 配置启动即可

systemctl daemon-reload
systemctl start kubelet
systemctl enable kubelet
systemctl start kube-proxy
systemctl enable kube-proxy

最后在 master 签发一下相关证书

kubectl certificate approve csr-z090b

整体部署完成后如下

未分类

六、部署 Calico

网路组件这里采用 Calico,Calico 目前部署也相对比较简单,只需要创建一下 yml 文件即可,具体可参考 Calico 官方文档

Cliaco 官方文档要求 kubelet 启动时要配置使用 cni 插件 –network-plugin=cni,同时 kube-proxy 使用 –masquerade-all 启动,所以需要修改所有 kubelet 和 proxy 配置文件增加这两项,以下默认为这两项已经调整完毕,这里不做演示

# 获取相关 Cliaco.yml
wget http://docs.projectcalico.org/v2.3/getting-started/kubernetes/installation/hosted/calico.yaml

# 修改 Etcd 相关配置,以下列出主要修改部分(etcd 证书内容需要被 base64 转码)

sed -i 's@.*etcd_endpoints:.*@  etcd_endpoints: "https://192.168.1.11:2379,https://192.168.1.12:2379,https://192.168.1.13:2379"@gi' calico.yaml

export ETCD_CERT=`cat /etc/etcd/ssl/etcd.pem | base64 | tr -d 'n'`
export ETCD_KEY=`cat /etc/etcd/ssl/etcd-key.pem | base64 | tr -d 'n'`
export ETCD_CA=`cat /etc/etcd/ssl/etcd-root-ca.pem | base64 | tr -d 'n'`

sed -i "s@.*etcd-cert:.*@  etcd-cert: ${ETCD_CERT}@gi" calico.yaml
sed -i "s@.*etcd-key:.*@  etcd-key: ${ETCD_KEY}@gi" calico.yaml
sed -i "s@.*etcd-ca:.*@  etcd-ca: ${ETCD_CA}@gi" calico.yaml

sed -i 's@.*etcd_ca:.*@  etcd_ca: "/calico-secrets/etcd-ca"@gi' calico.yaml
sed -i 's@.*etcd_cert:.*@  etcd_cert: "/calico-secrets/etcd-cert"@gi' calico.yaml
sed -i 's@.*etcd_key:.*@  etcd_key: "/calico-secrets/etcd-key"@gi' calico.yaml

sed -i '[email protected]/[email protected]/18@gi' calico.yaml

执行部署操作,注意,在开启 RBAC 的情况下需要单独创建 ClusterRole 和 ClusterRoleBinding

kubectl create -f calico.yaml
kubectl apply -f http://docs.projectcalico.org/v2.3/getting-started/kubernetes/installation/rbac.yaml

部署完成后如下

未分类

最后测试一下跨主机通讯

# 创建 deployment
cat << EOF >> demo.deploy.yml
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: demo-deployment
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: demo
    spec:
      containers:
      - name: demo
        image: mritd/demo
        ports:
        - containerPort: 80
EOF
kubectl create -f demo.deploy.yml

exec 到一台主机 pod 内 ping 另一个不同 node 上的 pod 如下

未分类

七、部署 DNS

7.1、DNS 组件部署

DNS 部署目前有两种方式,一种是纯手动,另一种是使用 Addon-manager,目前个人感觉 Addon-manager 有点繁琐,所以以下采取纯手动部署 DNS 组件

DNS 组件相关文件位于 kubernetes addons 目录下,把相关文件下载下来然后稍作修改即可

# 获取文件
mkdir dns && cd dns
wget https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/dns/kubedns-cm.yaml
wget https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/dns/kubedns-sa.yaml
wget https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/dns/kubedns-svc.yaml.sed
wget https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/dns/kubedns-controller.yaml.sed
mv kubedns-controller.yaml.sed kubedns-controller.yaml
mv kubedns-svc.yaml.sed kubedns-svc.yaml
# 修改配置
sed -i 's/$DNS_DOMAIN/cluster.local/gi' kubedns-controller.yaml
sed -i 's/$DNS_SERVER_IP/10.254.0.2/gi' kubedns-svc.yaml
# 创建(我把所有 yml 放到的 dns 目录中)
kubectl create -f ../dns

接下来测试 DNS,测试方法创建两个 deployment 和 svc,通过在 pod 内通过 svc 域名方式访问另一个 deployment 下的 pod,相关测试的 deploy、svc 配置在这里不在展示,基本情况如下图所示

未分类

未分类

7.2、DNS 自动扩容部署

关于 DNS 自动扩容详细可参考https://kubernetes.io/docs/tasks/administer-cluster/dns-horizontal-autoscaling/

以下直接操作

首先获取 Dns horizontal autoscaler 配置文件

wget https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/dns-horizontal-autoscaler/dns-horizontal-autoscaler-rbac.yaml
wget https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/dns-horizontal-autoscaler/dns-horizontal-autoscaler.yaml

然后直接 kubectl create -f 即可,DNS 自动扩容计算公式为 replicas = max( ceil( cores * 1/coresPerReplica ) , ceil( nodes * 1/nodesPerReplica ) ),如果想调整 DNS 数量(负载因子),只需要调整 ConfigMap 中对应参数即可,具体计算细节参考上面的官方文档

# 编辑 Config Map
kubectl edit cm kube-dns-autoscaler --namespace=kube-system

ubuntu使用kubeadm安装配置k8s(Kubernetes)

安装

翻墙使用root权限执行以下内容或者参考这里

wget https://coding.net/u/scaffrey/p/hosts/git/raw/master/hosts 
cp hosts /etc/hosts

安装

apt-get update && apt-get install -y apt-transport-https
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
cat <<EOF > /etc/apt/sources.list.d/kubernetes.list
deb http://apt.kubernetes.io/ kubernetes-xenial main
EOF
apt-get update
apt-get install -y docker.io
apt-get install -y kubelet kubeadm kubectl kubernetes-cni

配置master节点

在master节点执行以下命令

kubeadm init  --pod-network-cidr 10.244.0.0/16

使master node参与工作负载

kubectl taint nodes --all node-role.kubernetes.io/master-

安装网络

kubectl create -f https://github.com/coreos/flannel/raw/master/Documentation/kube-flannel-rbac.yml
kubectl create -f  https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

配置worker节点

执行初始化master节点后打印的最后一行

kubeadm reset
kubeadm join --token 6aa93f.04f7fbce49b7f3bb 222.20.101.106:6443

使用

使用kubectl的run命令创建deployment

kubectl run nginx --image=nginx:1.10.0
kubectl get pods -o wide

使用expose 将端口暴露出来

kubectl expose deployment nginx --port 80 --type LoadBalancer
kubectl get services -o wide

通过scale命令扩展应用

kubectl scale deployments/nginx --replicas=4
kubectl get pods -o wide

创建nginx版本

更新应用镜像,滚动更新应用镜像

kubectl set image deployments/nginx nginx=qihao/nginx

确认更新

kubectl rollout status deployments/nginx 

回滚到之前版本

kubectl rollout undo deployments/nginx 

负载均衡(不停的刷新服务的地址,过段时间会有变化)

kubectl exec -it nginx-2027219757-r1sqm bash
uname -n > /usr/share/nginx/html/index.html 

结束

kubectl delete deployment nginx && kubectl delete service nginx
kubectl get services -o wide
kubectl get pods -o wide
kubectl get nodes