Spark是新一代分布式内存计算框架,Apache开源的顶级项目。相比于Hadoop Map-Reduce计算框架,Spark将中间计算结果保留在内存中,速度提升10~100倍;同时它还提供更丰富的算子,采用弹性分布式数据集(RDD)实现迭代计算,更好地适用于数据挖掘、机器学习算法,极大提升开发效率。
Docker是轻量级虚拟化容器技术,具有轻便性、隔离性、一致性等特点,可以极大简化开发者的部署运维流程,降低服务器成本。
Kubernetes是Google开源的容器集群管理系统,提供应用部署、维护、 扩展等功能,能够方便地管理大规模跨主机的容器应用。
相比于在物理机上部署,在Kubernetes集群上部署Spark集群,具有以下优势:
-
快速部署:安装1000台级别的Spark集群,在Kubernetes集群上只需设定worker副本数目replicas=1000,即可一键部署。
-
快速升级:升级Spark版本,只需替换Spark镜像,一键升级。
-
弹性伸缩:需要扩容、缩容时,自动修改worker副本数目replicas即可。
-
高一致性:各个Kubernetes节点上运行的Spark环境一致、版本一致
-
高可用性:如果Spark所在的某些node或pod死掉,Kubernetes会自动将计算任务,转移到其他node或创建新pod。
-
强隔离性:通过设定资源配额等方式,可与WebService应用部署在同一集群,提升机器资源使用效率,从而降低服务器成本。
接下来我们将介绍,如何使用 Docker和Kubernetes创建Spark集群(其中包含1个Spark-master和N个Spark-worker)。
参考文档:https://github.com/kubernetes/kubernetes/tree/master/examples/spark
首先需要准备以下工具:
● 安装并运行 kubernetes 集群
● 安装 kubectl 命令行工具
一、构建Docker镜像
1. 从源码build:
下载:https://github.com/kubernetes/application-images/blob/master/spark
docker build -t index.caicloud.io/spark:1.5.2 . docker build -t index.caicloud.io/zeppelin:0.5.6 zeppelin/
连接国外网络较慢,构建镜像的时间有些长,请耐心等待……
2. 从镜像仓库pull:
a) 才云科技的镜像仓库(index.caicloud.io)
docker login index.caicloud.io docker pull index.caicloud.io/spark:1.5.2 docker pull index.caicloud.io/zeppelin:0.5.6
b) DockerHub的镜像仓库(index.docker.io)
docker login index.docker.io docker pull index.docker.io/caicloud/spark:1.5.2 docker pull index.docker.io/caicloud/zeppelin:0.5.6
二、在Kubernetes上创建Spark集群
首先下载创建Kubernetes应用所需的Yaml文件: https://github.com/caicloud/public/tree/master/spark
第一步:创建命名空间namespace
Kubernetes通过命名空间,将底层的物理资源划分成若干个逻辑的“分区”,而后续所有的应用、容器都是被部署在一个具体的命名空间里。每个命名空间可以设置独立的资源配额,保证不同命名空间中的应用不会相互抢占资源。此外,命名空间对命名域实现了隔离,因此两个不同命名空间里的应用可以起同样的名字。创建命名空间需要编写一个yaml文件:
# namespace/namespace-spark-cluster.yaml apiVersion: v1 kind: Namespace metadata: name: "spark-cluster" labels: name: "spark-cluster"
创建Namespace: $ kubectl create -f namespace/namespace-spark-cluster.yaml 查看Namespace: $ kubectl get ns NAME LABELS STATUS default <none> Active spark-cluster name=spark-cluster Active 使用Namespace: (${CLUSTER_NAME}和${USER_NAME}可在kubeconfig文件中查看) $ kubectl config set-context spark --namespace=spark-cluster --cluster=${CLUSTER_NAME} --user=${USER_NAME} $ kubectl config use-context spark
第二步:启动master服务
先创建Spark-master的ReplicationController,然后创建spark所提供的两个Service(spark-master-service,spark-webui)。让Spark-workers使用spark-master-service来连接Spark-master,并且通过spark-webui来查看集群和任务运行状态。
1) 创建ReplicationController:
Kubernetes追求高可用设计,通过Replication Controller来保证每个应用时时刻刻会有指定数量的副本在运行。例如我们通过编写一个Replication Controller来运行一个nginx应用,就可以在yaml中指定5个默认副本。Kubernetes会自动运行5个nginx副本,并在后期时时对每一个副本进行健康检查(可以支持自定义的检查策略)。当发现有副本不健康时,Kubernetes会通过自动重启、迁移等方法,保证nginx会时刻有5个健康的副本在运行。对于spark-master,目前我们指定其副本数为1 (replicas: 1);对于spark-worker,我们指定其副本数为N (replicas: N,N >= 1)。
spark-master-controller.yaml可参考如下:
# replication-controller/spark-master-controller.yaml kind: ReplicationController apiVersion: v1 metadata: name: spark-master-controller spec: replicas: 1 selector: component: spark-master template: metadata: labels: component: spark-master spec: containers: - name: spark-master image: index.caicloud.io/spark:1.5.2 command: ["/start-master"] ports: - containerPort: 7077 - containerPort: 8080 resources: requests: cpu: 100m
创建Master-ReplicationController: $ kubectl create -f replication-controller/spark-master-controller.yaml replicationcontroller "spark-master-controller" created
2) 创建Master-Service:
Kubernetes追求以服务为中心,并推荐为系统中的应用创建对应的Service。以nginx应用为例,当通过Replication Controller创建了多个nginx的实例(容器)后,这些不同的实例可能运行在不同的节点上,并且随着故障和自动修复,其IP可能会动态变化。为了保证其他应用可以稳定地访问到nginx服务,我们可以通过编写yaml文件为nginx创建一个Service,并指定该Service的名称(如nginx-service);此时,Kubernetes会自动在其内部一个DNS系统中(基于SkyDNS 和etcd实现)为其添加一个A Record, 名字就是 “nginx-service”。随后,其他的应用可以通过 nginx-service来自动寻址到nginx的一个实例(用户可以配置负载均衡策略)。
spark-master-service.yaml可参考如下:
# service/spark-master-service.yaml kind: Service apiVersion: v1 metadata: name: spark-master spec: ports: - port: 7077 targetPort: 7077 selector: component: spark-master
创建Master-Service: $ kubectl create -f service/spark-master-service.yaml service "spark-master"created
3) 创建WebUI-Service:
如上所述,Service会被映射到后端的实际容器应用上,而这个映射是通过Kubernetes的标签以及Service的标签选择器实现的。例如我们可以通过如下的spark-web-ui.yaml来创建一个WebUI的Service, 而这个Service会通过 “selector: component: spark-master”来把WebUI的实际业务映射到master节点上:
# service/spark-webui.yaml kind: Service apiVersion: v1 metadata: name: spark-webui namespace: spark-cluster spec: ports: - port: 8080 targetPort: 8080 selector: component: spark-master
创建spark-webui-service: $ kubectl create -f service/spark-webui.yaml service "spark-webui" created
完成创建ReplicationController(rc)、Service(svc)后,检查 Master 是否能运行和访问:
$ kubectl get rc NAME DESIRED CURRENT AGE spark-master-controller 1 1 23h $ kubectl get svc NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE spark-master 10.254.106.29 <none> 7077/TCP 1d spark-webui 10.254.66.138 <none> 8080/TCP 18h $ kubectl get pods NAME READY STATUS RESTARTS AGE spark-master-controller-b3gbf 1/1 Running 0 23h
确认master正常运行后,再使用Kubernetes proxy连接Spark WebUI:
kubectl proxy --port=8001
然后通过http://localhost:8001/api/v1/proxy/namespaces/spark-cluster/services/spark-webui/查看spark的任务运行状态。
第三步:启动 Spark workers
Spark workers 启动时需要 Master service处于运行状态,我们可以通过修改replicas来设定worker数目(比如设定 replicas: 4,即可建立4个Spark Worker)。注意我们可以为每一个worker节点设置了CPU和内存的配额,保证Spark的worker应用不会过度抢占集群中其他应用的资源。
spark-worker-controller.yaml可参考如下:
# replication-controller/spark-worker-controller.yaml kind: ReplicationController apiVersion: v1 metadata: name: spark-worker-controller spec: replicas: 4 selector: component: spark-worker template: metadata: labels: component: spark-worker spec: containers: - name: spark-worker image: index.caicloud.io/spark:1.5.2 command: ["/start-worker"] ports: - containerPort: 8081 resources: requests: cpu: 100m
创建spark-worker的ReplicationController:
$ kubectl create -f replication-controller/spark-worker-controller.yaml replicationcontroller"spark-worker-controller" created
查看 workers是否正常运行
1. 通过WebUI查看: worker就绪后应该出现在UI中。(这可能需要一些时间来拉取镜像并启动pods)
2. 通过kubectl查询状态(可看到spark-worker都已经正常运行):
</pre><p><pre name="code" class="plain">$ kubectl get pods NAME READY STATUS RESTARTS AGE spark-master-controller-b3gbf 1/1 Running 0 1d spark-worker-controller-ill4z 1/1 Running 1 2h spark-worker-controller-j29sc 1/1 Running 0 2h spark-worker-controller-siue2 1/1 Running 0 2h spark-worker-controller-zd5kb 1/1 Running 0 2h
第四步:提交Spark任务
两种方式:Spark-client或Zeppelin。
通过Spark-client,可以利用spark-submit来提交复杂的Python脚本、Java/Scala的jar包代码;
通过Zeppelin,可以直接在命令行或UI编写简单的spark代码。
1. 通过Spark-client提交任务
$ kubectl get pods | grep worker
NAME READY STATUS RESTARTS AGE spark-worker-controller-1h0l7 1/1 Running 0 4h spark-worker-controller-d43wa 1/1 Running 0 4h spark-worker-controller-ka78h 1/1 Running 0 4h spark-worker-controller-sucl7 1/1 Running 0 4h
$ kubectl exec spark-worker-controller-1h0l7 -it bash $ cd /opt/spark
# 提交python spark任务 ./bin/spark-submit \ --executor-memory 4G \ --master spark://spark-master:7077 \ examples/src/main/python/wordcount.py \ "hdfs://hadoop-namenode:9000/caicloud/spark/data"
# 提交scala spark任务 ./bin/spark-submit --executor-memory 4G --master spark://spark-master:7077 --class io.caicloud.LinearRegression /nfs/caicloud/spark-mllib-1.0-SNAPSHOT.jar "hdfs://hadoop-namenode:9000/caicloud/spark/data"
2. 通过Zeppelin提交任务
使用Zeppelin提交时有两种方式:pod exec 和 zeppelin-UI。我们先创建zeppelin的ReplicationController:
$ kubectl create -f replication-controller/zeppelin-controller.yaml replicationcontroller "zeppelin-controller"created
查看zeppelin: $ kubectl get pods -l component=zeppelin NAME READY STATUS RESTARTS AGE zeppelin-controller-5g25x 1/1 Running 0 5h
a) 通过zeppelin exec pods方式提交
$ kubectl exec zeppelin-controller-5g25x -it pyspark
b) 通过zeppelin UI方式提交
使用已创建的Zeppelin pod,设置WebUI的映射端口:
$ kubectl port-forward zeppelin-controller-5g25x 8080:8080
访问 http://localhost:8080/,并提交测试代码:
使用Spark的问题
● Spark的master与worker无法通信
解决办法:查看Spark Master Service是否正常
● Spark资源与调度问题
a) worker数量不要超过kubernetes集群的节点数量(如果超过,spark性能会下降)
b) executor-memory不要超过机单台器最大内存,executor-cores不要超过单台机器的CPU核数
c) 如果遇到insufficient resources问题,检查是否有其他任务在运行并kill
d) 同一个kubernetes节点上,可能会分配多个worker,导致性能下降(这时最好重新创建worker)
e) 内存、磁盘IO、网络IO、CPU都可能成为Spark的性能瓶颈
● 任务运行时的问题
SocketTimeoutException: Accept timeout —— spark版本为1.5.2时,试试将jdk版本由1.8降低至1.7
使用Zeppelin的问题
● Zeppelin pod很大,拉取镜像可能会消耗一段时间,取决于你的网络条件
● 第一次运行Zeppelin时, pipeline可能会花费很多时间(约一分钟),需要比较多的时间来初始化。
● kubectl port-forward可能不会长时间保持稳定状态。如果发现Zeppelin变成断开(disconnected),port-forward很可能出现故障,这时需要重启
● 从ZeppelinUI提交任务,运行时间不稳定(波动较大)
为了测试Spark性能,我们需要使用大量数据,但kubernetes节点所在的机器磁盘空间有限(20G)。通过为每台机器挂载NFS/GlusterFS大网盘,解决大数据存储的问题。
接下来我们将介绍,如何使用Spark从NFS中读取数据,以及其中遇到的问题。
1. 首先为每个kubernetes节点安装nfs-client,挂载nfs网盘(假设NFS-server为10.57.*.33,数据存于/data1T5目录下)
$ sudo apt-get install nfs-common $ sudo mkdir -p /data1T5 $ sudo mount -t nfs 10.57.*.33:/data1T5 /data1T5
2. 声明PersistentVolumes(pv)和PersistentVolumeClaims(pvc),使得Kubernetes能连接NFS数据网盘:
$ kubectl create -f nfs/nfs_pv.yaml $ kubectl create -f nfs/nfs_pvc.yaml
# nfs/nfs_pv.yaml apiVersion: v1 kind: PersistentVolume metadata: name: spark-cluster spec: capacity: storage: 1535Gi accessModes: - ReadWriteMany nfs: server: 10.57.*.33 path: "/data1T5"
# nfs/nfs_pvc.yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: spark-cluster spec: accessModes: - ReadWriteMany resources: requests: storage: 1535Gi
3. 为Spark的ReplicationController增加volumeMounts和volumes两项,并重新create,使得Spark容器能访问NFS数据。
修改spark-master-controller.yaml和spark-worker-controller.yaml,存为nfs/spark-master-controller.nfs.yaml 和 nfs/spark-worker-controller.nfs.yaml
$ kubectl delete rc spark-master-controller $ kubectl create -f nfs/spark-master-controller.nfs.yaml $ kubectl delete rc spark-worker-controller $ kubectl create -f nfs/spark-worker-controller.nfs.yaml
4. 使用exec方式进入master/worker所在的pod,可以看到nfs挂载的/data1T5目录:
$ kubectl exec spark-worker-controller-1h0l7 -it bash root@spark-worker-controller-1h0l7:/# ls -al /data1T5/
成功挂载后,即可在Spark程序中,使用sc.textFile()读取NFS数据。
注意事项:
a) 如果希望使用spark从nfs中读取数据,必须事先在kubernetes集群的所有节点上安装nfs-client
b) 使用spark从多台nfs-client读取一台nfs-server数据时,遇到IO瓶颈,读取速率只有30MB~40MB/s
本机搭建三节点 k8s 集群
本文的侧重点在实际操作,k8s 组件基本概念相关的信息请参考 k8s 官方文档或 Kubernetes 指南 – by feiskyer
https://kubernetes.io/docs/concepts/
https://github.com/feiskyer/kubernetes-handbook
如果对于本文有什么建议、意见及疑问,欢迎提 issue,或直接发邮件交流(邮箱很容易能找到,不再提供)。
环境依赖
本文假设读者会使用 Linux 命令行。
k8s 的镜像源在墙外,所以需要读者掌握科学上网的技能。这个部分不属于本文的描述范围,我使用的方案是 Shadowsocks + Privoxy,有需要可以跟我交流。
- Docker : 1.13.1
- kube* : 1.10
- flannel : 0.10.0
- virtualBox: 5.2.8
- OS : ubuntu-16.04.4-server-amd64.iso
virtualBox 的版本不太重要,Docker 和 kube* 的版本最好使用 k8s 推荐的版本,否则可能会有问题,推荐的 Docker 版本可以在版本的 release 文档中查看。OS 的版本不同,后面的一些配置的方法会略有不同。
搭建目标
flannel.1 是 每台机器上的一个 VNI,通过 ifconfig 命令可以查看该接口的信息。
从任意一台机器 ping 另外两台机器 flanel.1 的 IP 能通就算集群搭建成功。
# from master
$ ping 10.244.1.0
PING 10.244.1.0 (10.244.1.0) 56(84) bytes of data.
64 bytes from 10.244.1.0: icmp_seq=1 ttl=64 time=0.659 ms
64 bytes from 10.244.1.0: icmp_seq=2 ttl=64 time=0.478 ms
64 bytes from 10.244.1.0: icmp_seq=3 ttl=64 time=0.613 ms
^C
--- 10.244.1.0 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1999ms
rtt min/avg/max/mdev = 0.478/0.583/0.659/0.079 ms
$ ping 10.244.2.0
PING 10.244.2.0 (10.244.2.0) 56(84) bytes of data.
64 bytes from 10.244.2.0: icmp_seq=1 ttl=64 time=0.459 ms
64 bytes from 10.244.2.0: icmp_seq=2 ttl=64 time=0.504 ms
64 bytes from 10.244.2.0: icmp_seq=3 ttl=64 time=0.553 ms
^C
--- 10.244.2.0 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2058ms
rtt min/avg/max/mdev = 0.459/0.505/0.553/0.042 ms
k8s 个组件之间的关系
其实这个没必要多说,Kubernetes Components或 Kubernetes 核心组件 – by feiskyer讲的已经非常好了,这里提到只是强调一下这部分的重要性。
https://kubernetes.io/docs/concepts/overview/components/
https://kubernetes.feisky.xyz/zh/components/
k8s Pod 网络模型简介
图片来源:一次Flannel和Docker网络不通定位问题
http://www.cnblogs.com/ericnie/p/8028681.html
为了省事,我直接引用了别人画的模型图。对于本次搭建的集群模型简单描述如下:
- cni0 和 flannel.1 都是 VNI,由 flannel 组件创建,集群搭建完成后可以通过 ifconfig 进行查看。
- flannel 组件 在每台机器上运行了一个 flanneld,它是用来转发流量,解决主机间通信的问题。
- enp0s8 是 virtualBox 的 Host-Only 适配器。
配置流程
使用 virtualBox 创建三台虚拟机
virtualBox 安装比较简单,不再介绍,GUI 工具用起来也很方便,这部分只介绍我认为需要提示的部分。
- 默认只有一个 NAT 适配器,添加一个 Host-Only Adapter。NAT 适配器是虚拟机用来访问互联网的,Host-Only 适配器是用来虚拟机之间通信的。
- 以 Normal Start 方式启动虚拟机安装完系统以后,因为是 server 版镜像,所以没有图形界面,直接使用用户名密码登录即可。
- 修改配置,enp0s8 使用静态 IP。配置请参考 SSH between Mac OS X host and Virtual Box guest。注意配置时将其中的网络接口名改成你自己的 Host-Only Adapter 对应的接口。
- 一台虚拟机创建完成以后可以使用 clone 方法复制出两台节点出来,注意 clone 时为新机器的网卡重新初始化 MAC 地址。
- 三台虚拟机的静态 IP 都配置好以后就可以使用 ssh 在本地主机的终端上操作三台虚机了。虚机使用 Headless Start 模式启动
https://gist.github.com/c-rainstorm/1bbd44b388acd35ca6eaf07d1fbd9bc7
安装 Docker
三台都装
当前 Ubuntu 的 docker 版本刚好合适,所以可以直接安装,但是有必要提前查看一下 docker 版本,以免装错。
# apt search docker.io
apt-get update
apt-get install -y docker.io
systemctl enable docker
systemctl start docker
docker 配置代理。镜像源在墙外,docker pull image 需要代理
mkdir -p /etc/systemd/system/docker.service.d
cat <<EOF >/etc/systemd/system/docker.service.d/http-proxy.conf
[Service]
Environment="HTTP_PROXY=https://192.168.99.1:8118/"
Environment="HTTPS_PROXY=https://192.168.99.1:8118/"
Environment="NO_PROXY=localhost,127.0.0.1,localaddress,.localdomain.com"
EOF
systemctl daemon-reload
systemctl restart docker
测试配置
docker info | grep Proxy # 有输出说明配置成功
docker pull gcr.io/google-containers/busybox:1.27 # pull 成功代表工作正常。
Google 镜像库
https://console.cloud.google.com/gcr/images/google-containers/GLOBAL?project=google-containers
安装 kube* 组件
三台都装
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 kubelet kubeadm kubectl
systemctl enable kubelet
systemctl start kubelet
Master 节点配置 cgroup driver
docker info | grep -i cgroup # 一般是 cgroupfs
cat /etc/systemd/system/kubelet.service.d/10-kubeadm.conf # --cgroup-driver 对应值默认是 systemd
#两个值不一致的话使用以下命令修改
sed -i "s/cgroup-driver=systemd/cgroup-driver=cgroupfs/g" /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
#重启 kubelet
systemctl daemon-reload
systemctl restart kubelet
curl 访问的是墙外的网站,无法访问的话可以配置系统代理。
http://192.168.99.1:8118/ 是我本地使用的 HTTP 代理,Privoxy 监听 8118 端口,按照实际情况修改该地址。
# 全局代理,不推荐
cat <<EOF >>/etc/environment
http_proxy="http://192.168.99.1:8118/"
https_proxy="http://192.168.99.1:8118/"
no_proxy="master, node1, node2, 192.168.99.1"
EOF
source /etc/environment
#当前 shell,推荐
export http_proxy="http://192.168.99.1:8118/"
export https_proxy="http://192.168.99.1:8118/"
export no_proxy="master, node1, node2, 192.168.99.1"
apt 使用代理
cat <<EOF >>/etc/apt/apt.conf
Acquire::http::Proxy "http://192.168.99.1:8118/";
Acquire::https::Proxy "https://192.168.99.1:8118/";
EOF
搭建集群
禁用交换区
k8s 文档明确要求的。
三台都禁用
swapoff -a
初始化 master 节点
初始化过程会访问墙外网站,如果 init 不能顺利执行,请配置全局代理
kubeadm init --apiserver-advertise-address=192.168.99.200 --pod-network-cidr=10.244.0.0/16
- --apiserver-advertise-address=192.168.99.200 绑定 apiserver 到 master 节点的 Host-Only 适配器的地址,默认是绑到 NAT 的地址上,这样其他机器是永远也访问不到的。
- --pod-network-cidr=10.244.0.0/16 指定 pod 网络地址空间,我们使用 flannel 组件必须使用这个空间。
- kubeadm 的完整参考手册 kubeadm reference guide
- 推荐保存最后输出的 join 命令到文件(以免忘记或找不到了),方便添加节点到集群。如果忘了也找不到输出了,网上有方法生成哈希值,请自行查找。
配置 kubectl 访问集群
# root user
export KUBECONFIG=/etc/kubernetes/admin.conf
# non-root user
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# 从本地主机操作,需要在本地安装 kubectl 客户端
mkdir -p ~/.kube
scp <username>@192.168.99.200:/home/<username>/.kube/config ~/.kube/config # 从 master 复制配置文件到本地
测试配置
kubectl cluster-info #有正常输出即可
安装 flannel 网络
flannel 默认的监听接口是 NAT 适配器的接口,我们需要的是 Host-Only 适配器的接口,所以需要修改 kube-flannel.yml 文件
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
给 /opt/bin/flanneld 命令添加 --iface="enp0s8" 参数 # enp0s8 是 Host-Only 适配器对应的接口
kubectl apply -f kube-flannel.yml
测试配置
kubectl get pods --all-namespaces -o wide # 稍等一会,下载镜像需要一定时间,最后应该显示 flannel pods 是 Running 状态, kube-dns 也是 Running 状态
消除 master 隔离。默认 master 上不调度 pods,要允许另外的 pods 在 master 上运行请执行该命令
kubectl taint nodes --all node-role.kubernetes.io/master-
添加节点到集群
在节点上执行 kubeadm init 最后输出的 join 命令
kubeadm join --token <token> <master-ip>:<master-port> --discovery-token-ca-cert-hash sha256:<hash>
最后
feiskyer 为该搭建过程写了自动化脚本,有兴趣可以尝试一下。
https://github.com/feiskyer/ops
- k8s 官方文档 https://kubernetes.io/docs/concepts/
- Kubernetes 指南 – by feiskyer https://github.com/feiskyer/kubernetes-handbook
- 一次Flannel和Docker网络不通定位问题 http://www.cnblogs.com/ericnie/p/8028681.html
- coreos/flannel – README https://github.com/coreos/flannel/blob/master/README.md
- Installing kubeadm https://kubernetes.io/docs/setup/independent/install-kubeadm/
- Docker Ubuntu Behind Proxy https://stackoverflow.com/questions/26550360/docker-ubuntu-behind-proxy?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa
- Using kubeadm to Create a Cluster https://kubernetes.io/docs/setup/independent/create-cluster-kubeadm/