虚拟机和容器技术的实现了服务器计算环境的抽象和封装,能够做为服务器平台上的应用程序运行的软件实体。多台虚拟机和容器能够被部署在一台物理服务器上,或将多台服务器整合到较少数量的物理服务器上,可是容器技术不是为了彻底取代传统虚拟机技术,二者有本质的区别:node
虚拟机技术属于系统虚拟化,本质上就是在模拟一台真实的计算机资源,其中包括虚拟CPU,存储,以及各类虚拟硬件设备——这意味着它也拥有本身的完整访客操做系统;linux
容器技术则是应用虚拟化,使用沙箱机制虚拟出一个应用程序运行环境,每一个运行的容器实例都能拥有本身独立的各类命名空间(亦即资源)包括: 进程, 文件系统, 网络, IPC , 主机名等;nginx
虚拟机将整个操做系统运行在虚拟的硬件平台上, 进而提供完整的运行环境供应用程序运行,同时也须要消耗更过的宿主机硬件资源; 而Docker等容器化应用时使用的资源都是宿主机系统提供的,仅仅是在资源的使用上只是作了某种程度的隔离与限制.比起虚拟机,容器拥有更高的资源使用效率,实例规模更小、建立和迁移速度也更快.这意味相比于虚拟机,在相同的硬件设备当中,能够部署数量更多的容器实例,可是计算资源的隔离程度不如虚拟机,因此运行在同一台宿主机的实例更容易相互影响,甚至主机操做系统崩溃会直接影响运行在宿主机上的全部容器应用。git
在实际生产场景中,须要面临众多跨主机的容器协同工做,须要支持各类类型的工做负载,而且要知足可靠性,扩展性,以及面临随着业务增加而要解决的性能问题,以及相关的网络、存储、集群,从容器到容器云的进化随之出现。docker
构建一个容器云面临着众多的挑战,首先 Docker引擎的组网能力比较弱,在单一主机网络能提供较好的支持,但将Docker集群扩展到多台主机后,跨主机Docker容器之间的交互和网络的管理和维护将面临巨大的挑战,甚至难觉得继,所幸不少公司都开发了各自的产品来解决这个问题,典型的如Calico, Flannel, Weave,包括docker1.9版本后提供的Docker Overlay Network支持,其核心思想就是在将不一样主机上的容器链接到同一个虚拟网络,在这里咱们选择了来自CoreOS的Flannel来做为集群网路解决方案。后端
在生产环境中,最终面向业务应用须要的容器数量庞大,容器应用间的依赖关系繁杂,若是彻底依赖人工记录和配置这样的复杂的关联信息,而且要知足集群运行的部署,运行,监控,迁移,高可用等运维需求,实属力不从心,因此诞生了编排和部署的需求,能解决这类问题的工具备Swarm、Fleet、Kubernetes以及Mesos等,综合考虑从,最后悬着了来自Google的Kubernetes ---- 一个全径且全面的容器管理平台,具备弹性伸缩、垂直扩容、灰度升级、服务发现、服务编排、错误恢复及性能监测等功能,能够轻松知足众多业务应用的运行和维护。centos
容器云即以容器为资源分割和调度的基本单位,封装整个软件运行时环境,为开发者和系统管理员提供用于构建、发布和运行分布式应用的平台。最后用一张图示来归纳整个容器的生态技术栈:api
参考上文图示,以四台机器为例作规划,一台主机作master,其余三台主机作node节点,全部主机部署centos7, 按照角色为每台主机命名:安全
IP | 主机名 |
---|---|
10.1.10.101 | master |
10.1.10.102 | node1 |
10.1.10.103 | node2 |
10.1.10.104 | node3 |
每台主机须要作的配置是:服务器
/etc/yum.repos.d/CentOS-Base.repo
,完成以下修改:[base] name=CentOS-$releasever - Base - 163.com baseurl=http://mirrors.163.com/centos/7.4.1708/os/x86_64/ gpgcheck=0 enabled=1 [extras] name=CentOS-$releasever - Extras - 163.com baseurl=http://mirrors.163.com/centos/7.4.1708/extras/x86_64/ gpgcheck=0 enabled=1 [k8s-1.8] name=K8S 1.8 baseurl=http://onwalk.net/repo/ gpgcheck=0 enabled=1
10.1.10.101 master 10.1.10.102 node1 10.1.10.103 node2 10.1.10.104 node3
首先要实现跨物理机的容器访问——是不一样物理内的容器可以互相访问,四台机器,在master主机上部署etcd,三台机器安装flannel和docker。
主机 | 安装软件 |
---|---|
master | etcd |
node1 | flannel、docker |
node2 | flannel、docker |
node3 | flannel、docker |
简单的说flannel作了三件事情:
如上分所述,须要完成以下操做:
三个组件的启动顺序是: etcd->flanned->docker.
ETCD_LISTEN_CLIENT_URLS="http://10.1.11.101:2379" ETCD_ADVERTISE_CLIENT_URLS="http://10.1.11.101:2379"
systemctl restart etcd
etcdctl -C http://10.1.11.101:2379 set /flannel/network/config '{"Network": "192.168.0.0/16"}'
FLANNEL_ETCD_ENDPOINTS="http://master:2379" FLANNEL_OPTIONS='-etcd-prefix="/flannel/network"'
EnvironmentFile=-/run/flannel/docker.env
--exec-opt native.cgroupdriver=systemd -H unix:///var/run/docker.sock
systemctl daemon-reload systemctl restart flanneld systemctl restart docker
Kubenetes总体架构以下图所示,主要包括apiserver、scheduler、controller-manager、kubelet、proxy。
apiserver:kubernetes系统的入口,封装了核心对象的增删改查操做,以RESTFul接口方式提供给外部客户和内部组件调用。它维护的REST对象将持久化到etcd(一个分布式强一致性的key/value存储)。
scheduler:负责集群的资源调度,为新建的pod分配机器。
controller-manager:负责执行各类控制器,目前有两类:
在准备好快物理主机的集群网络后, 在master主机上安装kubernetes-master,其他三台节点主机安装kubernetes-node
主机 | 安装软件 |
---|---|
master | kubernetes-master、kubernetes-common、kubernetes-client |
node1 | kubernetes-node、kubernetes-common |
node2 | kubernetes-node、kubernetes-common |
node3 | kubernetes-node、kubernetes-common |
集群架构
基于CA签名的双向证书的生成过程以下:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ca.key -out ca.crt -subj "/CN=master"
建立证书配置文件 /etc/kubernetes/openssl.cnf ,在alt_names里指定全部访问服务时会使用的目标域名和IP; 由于SSL/TLS协议要求服务器地址需与CA签署的服务器证书里的subjectAltName信息一致
[req] req_extensions = v3_req distinguished_name = req_distinguished_name [req_distinguished_name] [ v3_req ] basicConstraints = CA:FALSE keyUsage = nonRepudiation, digitalSignature, keyEncipherment subjectAltName = @alt_names [alt_names] DNS.1 = kubernetes DNS.2 = kubernetes.default DNS.3 = kubernetes.default.svc DNS.4 = kubernetes.default.svc.cluster.local DNS.5 = localhost DNS.6 = master IP.1 = 127.0.0.1 IP.2 = 192.168.1.1 IP.3 = 10.1.10.101
最后两个IP分别是clusterIP取值范围里的第一个可用值、master机器的IP。 k8s会自动建立一个service和对应的endpoint,来为集群内的容器提供apiServer服务; service默认使用第一个可用的clusterIP做为虚拟IP,放置于default名称空间,名称为kubernetes,端口是443; openssl.cnf里的DNS1~4就是从容器里访问这个service时会使用到的域名.
mkdir -pv /etc/kubernetes/ca/ cd /etc/kubernetes/ca/ openssl genrsa -out server.key 2048 openssl req -new -key server.key -out server.csr -subj "/CN=master" -config ../openssl.cnf openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 9000 -extensions v3_req -extfile ../openssl.cnf
openssl verify -CAfile ca.crt server.crt
for NAME in client node1 node2 node3 do openssl genrsa -out $NAME.key 2048 openssl req -new -key $NAME.key -out $NAME.csr -subj "/CN=$NAME" openssl x509 -req -days 9000 -in $NAME.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out $NAME.crt done
openssl verify -CAfile ca.crt *.crt
kubectl config set-cluster k8s-cluster --server=https://10.1.10.101:6443 --certificate-authority=/etc/kubernetes/ca/ca.crt kubectl config set-credentials default-admin --certificate-authority=/etc/kubernetes/ca/ca.crt --client-key=/etc/kubernetes/ca/client.key --client-certificate=/etc/kubernetes/ca/client.crt kubectl config set-context default-system --cluster=k8s-cluster --user=default-admin kubectl config use-context default-system kubectl config view > /etc/kubernetes/kubeconfig
生成的配置文件内容以下:
apiVersion: v1 clusters: - cluster: certificate-authority: /etc/kubernetes/ca/ca.crt server: https://10.1.10.101:6443 name: k8s-cluster contexts: - context: cluster: k8s-cluster user: default-admin name: default-system current-context: default-system kind: Config preferences: {} users: - name: default-admin user: client-certificate: /etc/kubernetes/ca/client.crt client-key: /etc/kubernetes/ca/client.key
/etc/kubernetes/kubeconfig : 全部主机的共用配置文件 ca.crt : CA根证书 client.key client.crt : 提供给运行在k8s-master主机上的controllerManager、scheduler服务和kubectl工具使用 node1.key node1.crt : 提供给运行在node1主机上的kubelet, proxy服务使用 node2.key node2.crt : 提供给运行在node2主机上的kubelet, proxy服务使用 node3.key node3.crt : 提供给运行在node3主机上的kubelet, proxy服务使用
/etc/kubernetes/kubeconfig -> master 主机: /etc/kubernetes/kubeconfig ca.crt -> master 主机: /etc/kubernetes/ca/ca.crt node1.crt -> master 主机: /etc/kubernetes/ca/client.crt node1.key -> master 主机: /etc/kubernetes/ca/client.key
/etc/kubernetes/kubeconfig -> node1 主机: /etc/kubernetes/kubeconfig ca.crt -> node1 主机: /etc/kubernetes/ca/ca.crt node1.crt -> node1 主机: /etc/kubernetes/ca/client.crt node1.key -> node1 主机: /etc/kubernetes/ca/client.key
/etc/kubernetes/kubeconfig /etc/kubernetes/ca/ca.crt /etc/kubernetes/ca/client.crt /etc/kubernetes/ca/client.key
/etc/kubernetes/config 配置记录的全部组件的公共配置,如下服务启动的时候都用到:
/etc/kubernetes/config 内容以下:
KUBE_MASTER="--master=https://10.1.10.101:6443" KUBE_CONFIG="--kubeconfig=/etc/kubernetes/kubeconfig" KUBE_COMMON_ARGS="--logtostderr=true --v=1"
KUBE_ETCD_SERVERS="--storage-backend=etcd3 --etcd-servers=http://10.1.10.101:2379" KUBE_ADMISSION_CONTROL="--admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ResourceQuota" KUBE_API_ARGS="--service-node-port-range=80-65535 --service-cluster-ip-range=192.168.1.0/16 --bind-address=0.0.0.0 --insecure-port=0 --secure-port=6443 --client-ca-file=/etc/kubernetes/ca/ca.crt --tls-cert-file=/etc/kubernetes/ca/server.crt --tls-private-key-file=/etc/kubernetes/ca/server.key"
这里监听SSL/TLS的端口是6443;若指定小于1024的端口,有可能会致使启动apiServer启动失败
在master机器上,默认开8080端口提供未加密的HTTP服务,能够经过--insecure-port=0 参数来关闭
修改 kube-controller-manager 服务配置文件 /etc/kubernetes/controller-manager
KUBE_CONTROLLER_MANAGER_ARGS="--cluster-signing-cert-file=/etc/kubernetes/ca/server.crt --cluster-signing-key-file=/etc/kubernetes/ca/server.key --root-ca-file=/etc/kubernetes/ca/ca.crt --kubeconfig=/etc/kubernetes/kubeconfig"
KUBE_SCHEDULER_ARGS="--kubeconfig=/etc/kubernetes/kubeconfig"
systemctl restart kube-apiserver systemctl restart kube-controller-manager systemctl restart kube-scheduler
以node1主机为例,其他主机类同
KUBELET_ADDRESS="--address=0.0.0.0" KUBELET_HOSTNAME="--hostname-override=node1" KUBELET_POD_INFRA_CONTAINER="--pod-infra-container-image=docker.io/tianyebj/pod-infrastructure" KUBELET_ARGS="--kubeconfig=/etc/kubernetes/kubeconfig --cgroup-driver=systemd --fail-swap-on=false --runtime-cgroups=/systemd/system.slice --kubelet-cgroups=/systemd/system.slice"
KUBE_PROXY_ARG="--kubeconfig=/etc/kubernetes/kubeconfig"
systemctl restart kubelet systemctl restart kube-proxy
kubectl --kubeconfig=/etc/kubernetes/kubeconfig get nodes
nginx-rc-v1.yaml
apiVersion: v1 kind: ReplicationController metadata: name: nginx-v1 version: v1 spec: replicas: 3 selector: app: nginx version: v1 template: metadata: labels: app: nginx version: v1 spec: containers: - name: nginx image: nginx:v1 ports: - containerPort: 80
nginx-src.yaml
apiVersion: v1 kind: Service metadata: name: nginx spec: type: NodePort ports: - port: 80 targetPort: 80 nodePort: 80 selector: app: nginx
kubectl --kubeconfig=/etc/kubernetes/kubeconfig create -f nginx-rc-v1.yaml kubectl --kubeconfig=/etc/kubernetes/kubeconfig create -f nginx-srv.yaml
kubectl --kubeconfig=/etc/kubernetes/kubeconfig cale rc nginx --replicas=4
nginx-rc-v2.yaml
apiVersion: v1 kind: ReplicationController metadata: name: nginx-v2 version: v2 spec: replicas: 4 selector: app: nginx version: v2 template: metadata: labels: app: nginx version: v2 spec: containers: - name: nginx image: nginx:v2 ports: - containerPort: 80
kubectl --kubeconfig=/etc/kubernetes/kubeconfig rolling-update nginx-v2 -f nginx-rc-v2.yaml --update-period=10s
Pod是Kubernetes的基本操做单元,把相关的一个或多个容器构成一个Pod,一般Pod里的容器运行相同的应用。Pod包含的容器运行在同一个Minion(Host)上,看做一个统一管理单元,共享相同的volumes和network namespace/IP和Port空间。
Services也是Kubernetes的基本操做单元,是真实应用服务的抽象,每个服务后面都有不少对应的容器来支持,经过Proxy的port和服务selector决定服务请求传递给后端提供服务的容器,对外表现为一个单一访问接口,外部不须要了解后端如何运行,这给扩展或维护后端带来很大的好处。
Replication Controller确保任什么时候候Kubernetes集群中有指定数量的pod副本(replicas)在运行, 若是少于指定数量的pod副本(replicas),Replication Controller会启动新的Container,反之会杀死多余的以保证数量不变。Replication Controller使用预先定义的pod模板建立pods,一旦建立成功,pod 模板和建立的pods没有任何关联,能够修改pod 模板而不会对已建立pods有任何影响,也能够直接更新经过Replication Controller建立的pods。对于利用pod 模板建立的pods,Replication Controller根据label selector来关联,经过修改pods的label能够删除对应的pods。Replication Controller主要有以下用法:
Labels是用于区分Pod、Service、Replication Controller的key/value键值对,Pod、Service、 Replication Controller能够有多个label,可是每一个label的key只能对应一个value。Labels是Service和Replication Controller运行的基础,为了将访问Service的请求转发给后端提供服务的多个容器,正是经过标识容器的labels来选择正确的容器。一样,Replication Controller也使用labels来管理经过pod 模板建立的一组容器,这样Replication Controller能够更加容易,方便地管理多个容器,不管有多少容器。