虛擬機和容器技術的實現了服務器計算環境的抽象和封裝,能夠做爲服務器平臺上的應用程序運行的軟件實體。多臺虛擬機和容器能夠被部署在一臺物理服務器上,或將多臺服務器整合到較少數量的物理服務器上,可是容器技術不是爲了徹底取代傳統虛擬機技術,二者有本質的區別: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能夠更加容易,方便地管理多個容器,不管有多少容器。