天天看點

Docker 從入門到放棄K8s

Docker 從入門到放棄

K8s

K8sSVNOpenshiftDoker容器技術Docker部署Docker配置參數Docker指令使用registry鏡像建立私有倉庫使用Dockerfile制作鏡像Docker Volumedocker容器互聯基于路由的容器互聯namespaceDocker管理工具ReigstryKubernetesKubernetes重要概念Kubernets實踐Kubernetes的版本更新Kubernetes定義kubernetes部署示例Kubernets 對外Service多端口服務VolumeNamespaceETCDETCD叢集Kubernetes 核心原理ResourceQuota ControllerServiceAccount Controller與Token Controller容器健康檢查安全機制原理Authenication認證Auhorization授權Admission Control 插件叢集安全配置案例雙向認證配置簡單認證配置HTTP base認證Kuberntes 網絡原理網橋Iptables/Netfilter路由Docker的網絡實作Kubernetes的網絡實作開源的網絡元件直接路由Flannel安裝flannelOpen vSwitchk8s網絡案例K8s開發指南APIK8s運維管理Node的隔離:Node的擴容:Pod動态擴容和縮放更新資源對象的Label将Pod排程到指定Node上滾動更新Kubernetes的高可用方案Kubernetes Master元件的高可用方案k8s資源配額管理K8s監控cAdvisor容器日志kubernetes DNS服務配置test

SVN

Subversion 官網

http://subversion.tigris.org/

Openshift

案例新浪雲SAE openshift本身是一種套件

技術 描述
Kubernutes 管理容器的元件; 叢集管理 %80内容
Apache 對外接口服務, 以及賬号的管理
Git 代碼的管理, svn
Etd 非關系型資料庫
docker 容器 hub.docker.com 國内的docker倉庫, 時速雲 hub.tenxcloud.com 阿裡雲的docker

預設密碼是Asimov

隔離namespace的定義

Namespace 系統調用參數 隔離内容
UTS CLONE_NEWUTS 主機名與域名
IPC CLONE_NEWIPC 信号量、消息隊列和共享記憶體
PID CLONE_NEWPID 程序編号
Network CLONE_NEWNET 網絡裝置、網絡棧、端口等等
Mount CLONE_NEWNS 挂載點(檔案系統)
User CLONE_NEWUSER 使用者和使用者組

Docker官方提供的公共鏡像倉庫public registry http://registry.hub.docker.com/ 紅帽官方提供的公共鏡像倉庫 http://registry.access.redhat.com/

Doker

Docker被稱為第三代Pass平台 DotCloud, 主要基于Pass平台為開發者.

Docker的核心技術cgroups. 将一組程式定義為一個group, 在這個group中, 有配置設定好的特定比例的cpu時間, io時間, 可用記憶體大小等. 最早是由google工程師提出. cgroups的重要概念是"子系統", 也就是資源控制器, 每個子系統就是一個資源的配置設定器. 比如CPU子系統是控制CPU時間配置設定的. 首先需要挂載子系統, 然後才有control group. 筆記: http://blog.opskumu.com/docker.html

容器技術

LXC是linux containers的簡稱, 是一種基于容器的作業系統層級的虛拟化技術. 借助于namespace的隔離機制和cgroup限額功能, LXC提供了一套統一的API和工具來建立和管理容器. Namespace: 命名空間, 相當于平行宇宙, 每個命名空間互相隔離, 互不幹擾 LXC: 提供一個共享kernel的OS級别的虛拟化方法, 在執行時不用重複加載kernel, 由于共享kernel, 會導緻一些kernel參數沒辦法在某個特定容器内進行修改. AUFS: docker的檔案系統, 是一個能透明覆寫一或多個現有檔案系統的層狀檔案系統. 支援将不同目錄挂載到同一個虛拟檔案系統下, 可以把不同的目錄聯合在一起, 組成一個單一的目錄. 這是一種虛拟的檔案系統, 檔案系統不需要格式化, 直接挂載即可. 支援寫入複刻(copy on write). 差異存儲, 最大化公用底層的檔案系統. 容器不建議使用sshd服務. docker exec指令可以進入容器排查問題.

Docker部署

baseurl = https://yum.dockerproject.org/repo/main/centos/7 gpgkey = https://yum.dockerproject.org/gpg

禁用firewalld, 啟動iptables 檢視docker的基本資訊

docker info      

檢視docker版本

docker version      

檢視容器的日志

docker logs [containerID]      

Docker配置參數

配置檔案為/etc/sysconfig/docker OPTIONS用來控制Docker Daemon程序參數 -H 表示Docker Daemon綁定的位址, -H=unix:///var/run/docker.sock -H=tcp://0.0.0.0:2375 --registry-mirror 表示Docker Registry的鏡像位址 --registry-mirror=http://4bc5abeb.m.daocloud.io --insecure-registry 表示(本地) 私有Docker Registry的位址. --insecure-registry ${privateRegistryHost}:5000 --selinux-enabled是否開啟SELinux,預設開啟 --selinux-enabled=true --bip 表示網橋docker0使用指定CIDR網絡位址, --bip=172.17.42.1 -b 表示采用已經建立好的網橋, -b=xxx

OPTIONS=-H=unix:///var/run/docker.sock -H=tcp://0.0.0.0:2375 --registrymirror=http://4bc5abeb.m.daocloud.io --selinux-enabled=true      

docker的日志預設放到/var/log/messages中 查找docker image

docker search java      

docker run. docker run的指令結束了, container也就結束了

docker run [options] IMAGE[:TAG][Command][ARG...]
docker run -it java ps       

-d: 在背景執行 docker exec 可以進入到該容器中. 或者使用attach重新連接配接容器的會話. 如果是attach在退出的時候可能會将容器關閉 互動就使用 -i -t docker run 時 沒有指定--name, namedaemon會自動生成随機字元串UUID docker基礎指令, create隻是建立但是不會運作

docker create/start/stop/pause/unpause      

建立mysql容器

docker create --name mysqlsrv1 -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 mysql
-e: 提供環境變量      

然後對虛拟機通路3306端口就可以通路容器的mysql服務

docker exec -it mysqlsrv1 /bin/bash      

檢視環境變量, docker的配置檔案一般使用環境變量來定義

docker exec mysqlsrv1 env      

運作停止後的容器也會占用磁盤空間, 在一次性運作的容器後面添加 run -rm, 在執行後删除 将容器變成鏡像

docker commit <container> [repo:tag]      

docker可以在容器中額外挂載一些目錄, 比如可以添加一些ping的工具

docker run --privileged -v /sbin:/mnt/sbin -v /bin:/mnt      

Docker指令

coreOS開發, 于redhat合作, google提供Kubernetes管理工具. images相當于一個模闆, 實質就是一個歸檔包tar. 分為readonly隻讀檔和寫的層. image生成容器. 一個鏡像可以對應多個容器, 如果容器中需要進行寫操作, 則需要從images中copy一個.

直接下載下傳一個image

docker search rhel7
docker pull workstation.pod6.example.com:5000/library/rhel7      

執行一個容器

docker run --help
docker run -itd 275be1d3d070 "/bin/bash"
-i: interactive
-t: tty
-d: 背景運作      

修改docker image标簽

docker tag docker.io/ubuntu ubuntu:mini      

檢視鏡像的詳細資訊

docker inspect [id]      

删除鏡像

docker rmi [id]
	-f: 強制删除      

根據本地鏡像制作鏡像檔案

docker commit -m "Added a new file" -a "Docker Newbee" b1624e625c32 test
	-a: 作者資訊
	-m: 送出資訊
	-p: 送出時暫停容器運作      

模闆可以通過openvz的網站進行下載下傳https://download.openvz.org/template/precreated/

cat centos-6-x86_64-minimal.tar.gz |docker import - centos6:latest      

儲存和導入鏡像, 使用save和load

docker save -o ubuntu.tar test:latest       
docker load --input ubuntu.tar
docker load < ubuntu.tar      

還可以使用import導入容器

docker import 
cat test_for_run.tar| docker import - test/ubuntu:v1.0      

docker既可以使用docker load指令來導入鏡像存儲檔案到本地鏡像庫, 也可以使用docker import指令來導入一個容器快照到本地鏡像倉庫. 容器快照檔案将丢棄所有的曆史記錄和中繼資料資訊, 而鏡像存儲檔案将儲存完整記錄, 體積比較龐大. 建立容器 docker run相當于docker create 然後在docker exec

docker create  
	-t: 提供一個僞終端pseudo-tty
	-i: 讓容器保持打開狀态
	-d: 守護狀态運作Daemonized      

檢視容器日志

docker log <container id>      

檢視容器狀态

docker ps
	-a: 可以檢視離線的容器      

連接配接容器, attach在離開容器的時候會關閉容器

docker attach
docker exec -it
docker exec -it 213c4841716d "bin/bash"      

删除容器

docker rm
	-f: 強行終止并删除一個運作中的容器
	-l: 删除容器的連接配接, 單保留容器
	-v: 删除容器挂載的資料卷      

制作容器包

febootstrap -i bash -i wget -i net-tools -i openssh-server -i openssh-client rhel71 rhel71doc http://content.example.com/ose3.0/x86_64/dvd/rhel-7-server-rpms/      

import image到docker中

cd rhel71doc/
tar -c .|docker import - rehl71_stu6      

删除容器

docker rm      

修改image标簽

docker tag dl.dockerpool.com:5000/ubuntu:latest ubuntu:latest      

檢視image詳細資訊, 傳回的是一個json格式的消息, 也可以使用-f參數來指定某一個參數

docker inspect [imageid]      

建立容器 docker create, 讓docker配置設定一個僞終端pseudo-tty

docker create -it centos:6 "/bin/bash"      

啟動容器可以使用docker run 或者docker start

docker run centos /bin/echo "hello world"      

終止容器, 使用docker stop. 它首先向容器發送SIGTERM信号, 等待一段時間後(預設為10s), 在發送SIGKILL信号終止容器 也可以是用docker start

docker start [container id]      

使用docker attach附着到容器中

docker attach [container id]      

檢視某個容器的程序pid

docker inspect --format "{{ .State.Pid }}" [container id]      

使用nsenter登入到容器中

nsenter --target 6803 --mount --uts --ipc --net --pid      

使用registry鏡像建立私有倉庫

建立本地的鏡像倉庫

使用Dockerfile制作鏡像

建立鏡像的方法有三種, 基于已有鏡像建立, 基于本地模闆導入以及Dockerfile建立

Dockerfile 檔案配置

FROM rhel7
MAINTAINER Sun Ying 
EXPOSE 80
RUN yum -y install httpd
RUN echo "Sample welcome page" >/var/www/html/index.html
CMD /usr/sbin/httpd -DFOREGROUND      

執行buildfile, 指在目前目錄下查找Dockerfile, 并且将image命名為ying/webservice

docker build -t ying/webservice .      

因為制作buildfile的時候是在容器中執行的, 我們如果需要添加一些檔案到容器中. 則需要使用ADD進行添加 ADD hello.sh /bin/hello.sh

FROM rhel7
MAINTAINER Sun Ying 
EXPOSE 80
ADD hello.sh /bin/hello.sh
ENV WORD hello world
RUN /bin/hello.sh      

複雜案例: 制作ubuntu+java+tomcat+ssh server鏡像 ENTRYPOINT是告訴鏡像需要執行什麼指令, 即在鏡像被使用的時候執行的指令

FROM ubuntu
MAINTAINER Ying "[email protected]"
RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" >/etc/apt/sources.list
RUN apt-get update
RUN apt-get install -y openssh-server
RUN mkidr -p /var/run/sshd
RUN echo "root:123456"|chpasswd
RUN apt-get install python-software-properties
RUN add-apt-repository ppa:webupd8team/java
RUN apt-get update
RUN apt-get install -y vim wget curl oracle-java7-installer	 tomcat7
# 設定JAVA_HOME環境變量
RUN update-alternatives --display java 
RUN echo "JAVA_HOME=/usr/lib/jvm/java-7-oracle" >> /etc/environment 
RUN echo "JAVA_HOME=/usr/lib/jvm/java-7-oracle" >> /etc/default/tomcat7
# 開啟容器的22, 8080端口
EXPOSE 22
EXPOSE 8080
# 設定tomcat7初始化運作
ENTRYPOINT service tomcat7 start && /usr/sbin/sshd -D      

Supervisor可以啟動多個程序. supervisoer作為守護程序監管多個程序運作. 注意, docker的程式一定要放在前台執行. superviord還會去監管他所啟動的程序

[supervisord]
nodaemon=true
[program:sshd]
command=/usr/sbin/sshd -D
[program:apache2]
command=/bin/bash -c "source /etc/apache2/envvars && exec /usr/sbin/apache2 -DFOREGROUND"      

一般來說一個容器中應該隻執行一個程式, docker隻會監測容器中的前台程式是否執行正常. 程式的配置檔案如果放在鏡像中會對鏡像的更新帶來運維的成本. 一般來說可以放在環境變量中(ENV). 此外, 日志輸出也是docker的一個問題. 一般來說日志, 需要綁定到持久存儲. 或者使用syslog 端口映射的方式, 傳輸到主機上 使用etcd/zookeepr來管理配置變更資訊. 本身是key/value的架構

Docker Volume

/var/lib/docker/graph: 存放本地Image裡面的分層資訊 /var/lib/docker/devicemapper/devicemapper/data: 存儲了image和container的二進制資料檔案 /var/lib/docker/devicemapper/devicemapper/metadata: 存儲了相關的中繼資料 docker的data檔案是一個稀疏磁盤空間, 預設是100G, 實際使用的大小可以使用du來進行檢視. 每個容器的大小最大為10G. aufs drvier是docker最早期支援的driver, 是linux核心的一個更新檔集. ubuntu會使用 device mapper: 2.6之後引入的, 提供了一種邏輯裝置到實體裝置的映射架構, 是LVM2的核心. 支援塊級别的copy on write特性. VFS: 虛拟檔案系統, 不支援COW btrfs: 非常快, 仍然在進化中 高頻寫操作需要volume: 大量日志檔案系統, 資料庫系統等 可以使用volume

docker run -it -v /volume rhel7 /bin/bash      

使用docker inspect 檢視

"Volumes": {
        "/volume": "/var/lib/docker/volumes/ec3f9aecdffc0818aaec803ca5eccb60506ce3ca4b1bc7e0676
e763733d39ad3/_data"
    },
    "VolumesRW": {
        "/volume": true
    },      

也可以使用本機目錄挂載到docker容器中去

docker run --rm=true -it -v /storage /volume java /bin/bash
						  本機目錄	容器目錄      

volume的互聯, 基于資料容器的單主機互聯.

docker run --rm=true --privileges=true --volume-from=32dsdfadsfsf -it rhel7 /bin/bash      

docker容器互聯

容器間基于link互聯, 預設情況下docker允許container互通, 通過-icc=false關閉互通. 一旦關閉互通, 隻能通過-link name:alias 指令連接配接指定container

關閉容器互聯

/usr/bin/docker daemon --icc=false --iptables=true      

link的隔離是隔離容器端口的. link隻能解決一台主機之間的互聯.

docker run --rm=true --name=myjavaserver -it java /bin/bash
docker run --rm=true --link=myjavaserver:serverM1 -it java /bin/bash      

多台主機的話則無法使用link進行互聯. SOCAT是一個多功能的網絡工具, 可以用來做簡單的HTTP proxy

socat TCP4-LISTEN:6666 TCP4:proxy.company.com:8080      

最簡單常用的互聯方式: 端口映射. 使用docker-proxy

主控端的0.0.0.0:8080 --> 容器80
docker run -p "8080:80"
docker run --rm=true --name=mysqlserver -p 8066:3306 -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_USER=ying -e MYSQL_PASSWORD=nsadm -e MYSQL_DATABASE=testing workstation.pod0.example.com:5000/openshift3/mysql-55-rhel7      
docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 8066 -container-ip 172.17.0.5 -container-port 3306      

可以添加NAT

-A DOCKER ! -i docker0 -p tcp -m tcp --dport 8066 -j DNAT --to-destination 172.17.0.6:3306
-A DOCKER -d 172.17.0.6/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 3306 -j ACCEPT
-A POSTROUTING -s 172.17.0.6/32 -d 172.17.0.6/32 -p tcp -m tcp --dport 3306 -j MASQUERADE      

proxy每個port的映射要使用将近11MB的記憶體. 是以建議直接使用主控端網絡共享出來

docker run --rm=true --name=mysqlserver --net=host -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_USER=ying -e MYSQL_PASSWORD=nsadm -e MYSQL_DATABASE=testing workstation.pod0.example.com:5000/openshift3/mysql-55-rhel7      

多個容器公用一個網絡, 下面的例子中, 第二個容器使用了第一個容器的IP 位址

docker run --rm=true --name=mysqlserver -e MYSQL_ROOT_PASSWORD=123456 mysql
docker run --rm=true --net=container:mysqlserver java ip addr       

共享一個網絡的情況下, 互相通路可以通過localhost來進行彼此通路

docker run --rm=true --net=container:mysqlserver java curl localhost:3306      

基于路由的容器互聯

首先需要修改容器的IP位址, 這個時候經常會因為linux網橋自身的問題無法成功删除

ifconfig docker0 down 
brctl delbr docker0       

在兩台主機上分别執行

route add -net 172.18.0.0/16 gw 172.25.0.9
route add -net 172.17.0.0.16 gw 172.25.0.11
清理防火牆規則
iptables -F; iptables -t nat -F       

網絡将會以ovs為趨勢, docker官方提出了libnetwork的概念, 還在繼續的發展中.

namespace

平行宇宙. 在不同虛拟機中的網卡彼此是不可見的, tap是由軟體實作的. veth pari是用于不同network namespace間進行通信的方式, veth pari将一個network namespace資料發往另一個network namespace的veth. 檢視容器真正的pid

docker inspect -f '{{.State.Pid}}' [containerID]      

建立一個namespace網絡的軟連結

mkdir -p /var/run/netns
ln -s /proc/1469/ns/net /var/run/netns/1469      

此後就可以使用ip netns來進行操作和檢視

ip netns ls      

檢視容器中的ip位址

ip netns exec 1469 ip addr show       

在容器中檢視對端的接口

ip netns exec 1469 ethtool -S eth0      

在主控端中檢視網絡的veth應該與之相對應

安裝open vSwitch

yum install openvswitch      

添加網橋和gre隧道

ovs-vsctl add-br br0
ovs-vsctl   add-port   br0   gre0   --    set    Interface    gre0    type=gre options:remote_ip=172.25.0.9
brctl addif docker0 br0
ip link set dev br0 up
ip link set dev docker0 up
iptables -t nat -F;iptables -F
ip route add 172.17.0.0/16 dev docker0      

ovs-vsctl show

Bridge "br0"
    Port "br0"
        Interface "br0"
            type: internal
    Port "gre0"
        Interface "gre0"
            type: gre
            options: {remote_ip="172.25.0.9"}
ovs_version: "2.3.1-git3282e51"      

抓gre的包

tshark -i eth0 ip proto gre      

Docker管理工具

Shipyard和cAdvisor 安裝shiptyard

OPTIONS= -H=unix:///var/run/docker.sock -H=tcp://0.0.0.0:2375
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock\ shipyard/deploy start       

預設運作在8080端口, 使用者名密碼是admin/shipyard

cAdvisor是google推出的一個主要用于檢測容器狀态的工具, 也可以通過容器直接安裝

docker run --volume=/:/rootfs:ro --volume=/var/run:/var/run:rw --volume=/sys:/sys:ro --volume=/var/lib/docker/:/var/lib/docker:ro --publish=8082:8082 --detach=true --name=cadvisor google/cadvisor:latest --port=8082      

Reigstry

Registry包含一個或多個Repository Repository包含一個或多個Image. Image使用GUID表示, 有一個或多個Tag與之關聯

Kubernetes

Docker于CoreOS的恩怨情仇 cgroup最初是由google的工程師提出來, 後來被整合到核心中. Linux容器正式業界一直關注的Google基礎設施Borg和Omega的基礎之一, 基于之前Google開源的cgroup項目. Borg是一個生産環境的經驗下的論文. linux基金會介入coreOS, google, docker等公司的糾紛, 建立了OCP項目 2015年7月22日Google正式對外釋出Kubernetes v1.0 CNCF(Cloud Native Computing Foundation) 基金會

Kubernetes重要概念

Namingspace: 關聯resource. 資源隔離的一種手段, 不同NS中的資源不能互相通路 Resource: 關聯Namespace和ResourceQuta. 叢集中的一種資源對象, 處于某個命名空間中. 可以持久化存儲到Etcd中, 資源有狀态且可以配額. Label: 關聯Resouce,Label Selector. 一個Key-value值對. Master節點: 關聯工作節點Node. K8s叢集的管理節點, 負責叢集的管理. 提供叢集資源資料通路入口. 負責API Server程序, Controller Manager服務程序. Scheduler服務程序 Node節點: 關聯master節點. K8s中的工作節點, 啟動和管理k8s中的pod執行個體. 接受Master節點的管理指令, 運作着一個k8s的守護程序kubelet, 負載均衡器kube-proxy

kubectl describe node kubernetes-minion1      

Pod: 關聯Node和Serivce: 一組容器的一個"單一集合", K8s中的最小任務排程單元. 一個Pod中的容器共享資源(網絡, volume) Service: 關聯多個相同Label的Pod, 是一種微服務. 具有一個虛拟通路的位址(IP + Port). Replication Controller: 關聯多個相同Label的pod. Pod副本控制器, Volumes: 關聯Pod, 是Pod上的存儲卷.

Kubernets實踐

https://github.com/kubernetes/kubernetes/blob/release-1.0/docs/getting-started-guides/centos/centos_manual_config.md 要保證master/node節點之間可以互相通過域名通路 建立yum源

[virt7-testing]
name=virt7-testing
baseurl=http://cbs.centos.org/repos/virt7-testing/x86_64/os/
gpgcheck=0      

安裝kubernetes

yum install kubernetes      

安裝etcd, 他是kubernetes的鍵值資料庫系統

yum install etcd      

配置etcd

ETCD_NAME=master
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379,http://0.0.0.0:4001"
ETCD_ADVERTISE_CLIENT_URLS="http://master.example.com:2379,http://master.example.com:4001"      

驗證狀态

etcdctl set testdir/testkey0 1
etcdctl get testdir/testkey0
etcdctl -C http://master.example.com:4001 cluster-health      

公用配置/etc/kubernetes/config, 配置master資訊

KUBE_MASTER="--master=http://master.pod0.example.com:8080"
KUBE_ETCD_SERVERS="--etcd_servers=http://master:4001"      

在Master上面配置/etc/kubernetes/apiserver

KUBE_API_ADDRESS="--address=127.0.0.1"
KUBE_API_ADDRESS="--insecure-bind-address=0.0.0.0"
KUBE_API_PORT="--port=8080"
# KUBE_ETCD_SERVERS="--etcd_servers=http://127.0.0.1:2379"
# 預設ETCD啟動在2379端口      

在master上啟動服務etcd, kube-apiserver, kube-controller-manager, kube-scheduler. etcd是k8s的資料庫系統

for SERVICES in etcd kube-apiserver kube-controller-manager kube-scheduler;do systemctl restart $SERVICES; systemctl enable $SERVICES; systemctl status $SERVICES; done      

在node節點上進行配置/etc/kubernetes/kubelet

KUBELET_ADDRESS="--address=0.0.0.0"
KUBELET_PORT="--port=10250"
KUBELET_HOSTNAME="--hostname_override=node.pod0.example.com"
KUBELET_API_SERVER="--api_servers=http://master.pod0.example.com:8080"      

啟動kube-proxy和kubelet服務, 為了讓kube-proxy也能找到master需要配置config檔案聲明master節點位置 在master節點上可以檢查node節點的狀态是否注冊成功

kubectl get nodes
kubectl cluster-info      

修改docker配置

OPTIONS='--selinux-enabled=disabled       

在kube-scheduler和kube-controller-manager中添加

After=etcd.service
After=kube-apiserver.service
Requires=etcd.service
Requires=kube-apiserver.service      

Kubernetes的版本更新

非常簡單, 通過官網下載下傳最新版本的二進制包kubernetes.tar.gz, 解壓縮. 停止Master和Node上的服務, 将新版的可執行檔案複制到kubernetes的安裝目錄下.重新開機服務 kubectl

Available Commands:
  get            Display one or many resources
  describe       Show details of a specific resource or group of resources
  create         Create a resource by filename or stdin
  replace        Replace a resource by filename or stdin.
  patch          Update field(s) of a resource by stdin.
  delete         Delete a resource by filename, stdin, resource and name, or by resources and label selector.
  namespace      SUPERCEDED: Set and view the current Kubernetes namespace
  logs           Print the logs for a container in a pod.
  rolling-update Perform a rolling update of the given ReplicationController.
  scale          Set a new size for a Replication Controller.
  exec           Execute a command in a container.
  port-forward   Forward one or more local ports to a pod.
  proxy          Run a proxy to the Kubernetes API server
  run            Run a particular image on the cluster.
  stop           Gracefully shut down a resource by name or filename.
  expose         Take a replicated application and expose it as Kubernetes Service
  label          Update the labels on a resource
  config         config modifies kubeconfig files
  cluster-info   Display cluster info
  api-versions   Print available API versions.
  version        Print the client and server version information.
  help           Help about any command      

檢視namespace

kubectl get namespace
kubectl describe namespace default      

建立應答式檔案nginx.yaml

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: master.example.com:5000/nginx
    ports:
    - containerPort: 80      
kubectl create -f nginx-pod.yaml      

檢視events

kubectl get events      

搭建本地倉庫http://www.cnblogs.com/zhenyuyaodidiao/p/6500950.html

#KUBELET_POD_INFRA_CONTAINER="--pod-infra-container-image=registry.access.redhat.com/rhel7/pod-infrastructure:latest"       

每個Pod裡運作着一個特殊的被稱之為Pause的容器, 其他容器則為業務容器. 這些業務容器共享Pause容器的網絡棧和Volume挂在卷. 官方文檔https://docs.docker.com/registry/deploying/

Kubernetes定義

測試鏡像檔案在https://hub.docker.com/u/kubeguide/ Node資訊同步可以通過kube-controller-manager啟動參數 --node-sync-period 設定同步的時間周期 Node是自注冊的, 當kubelet的啟動參數中設定了--register-node為true時, kubelet會向apiserver注冊自己. Kubelet進行自注冊的啟動參數如下: --apiservers=: apiserver的位址 --kubeconfig=: 登入apiserver所需要憑據/證書的目錄 --cloud_provider=: 雲服務商位址, 用于擷取自身的metadata --regiter-node=: 設定為true表示自動注冊到apiserver上 通常在容器之間要使用link的方式互聯, 但是大量的link會消耗系統資源. 通過Pod的概念可以将多個容器組合在一個虛拟的"主機"内, 可以實作容器之間僅需要通過localhost就能互相通信了. 一個pod中的應用容器共享一組資源 PID命名空間: pod中的不同應用程式可以看到其他應用程式的程序ID 網絡命名空間: pod中的多個容器能夠通路同一個IP和端口範圍. IPC命名空間: Pod中的多個容器能夠使用systemV IPC或POSIX消息隊列進行通信 UTS命名空間: Pod中的多個容器共享一個主機名 volumes: 共享存儲卷, pod中的各個容器可以通路在pod級别定義的volumes

Pod的聲明周期是通過Replication Controller來管理的. Pod的生命周期過程包括: 通過模闆進行定義, 然後配置設定到一個Node上運作, 在pod所含容器運作結束後Pod也結束. Pod包含四種狀态. Pending: Pod定義正确, 送出到Master Running: Pod已經被配置設定到某個Node上. Succeeded: Pod中所有容器都成功結束 Failed: Pod中所有容器都結束了.

Label以key/value的形式附加到各種對象上, 如Pod, service, RC, Node. Label Selector分兩種, 基于等式的(Equality-based)和基于集合的(Set-Based). 基于等式的Label Selector, name=redis-slave; env != production; 基于集合的Label Selector, name in (redis-master, redis-slave) name not in (php-frontend) Replication Controller通過Label Selector來選擇要管理的Pod RC是Kubernetes系統的核心概念, 用于定義Pod副本的數量.

Service可以看做一組提供相同服務的pod對外通路的接口, Service作用于那些Pod是通過Label Selector來定義的. 建立本地倉庫, 首先使用阿裡加速器https://cr.console.aliyun.com/ pull registry并啟動

docker pull docker.io/registry 
docker run -d -p 5000:5000 --name=master.example.com --restart=always --privileged=true  --log-driver=none -v /home/data/registrydata:/tmp/registry registry      

k8s的node節點必須要安裝一個鏡像名為 gcr.io/google_containers/pause-amd64:3.0的鏡像. 可以從阿裡雲下載下傳.

docker pull registry.cn-hangzhou.aliyuncs.com/google-containers/pause-amd64:3.0      

重新tag鏡像名稱并且上傳到本地registry上

docker tag registry.cn-hangzhou.aliyuncs.com/google-containers/pause-amd64:3.0 master.ex
ample.com:5000/google_containers/pause-amd64:3.0
docker push master.example.com:5000/google_containers/pause-amd64:3.0      

然後修改docker中的--insecure-registry添加master.example.com:5000

kubernetes部署示例

建立redis-master-controller.yaml

apiVersion: v1
kind: ReplicationController
metadata:
  name: redis-master
  labels:
    name: redis-master
spec:
  replicas: 1
  selector:
    name: redis-master
  template:
    metadata:
      labels:
        name: redis-master
    spec:
      containers:
      - name: master
        image: master.example.com:5000/kubeguide/redis-master
        ports:
        - containerPort: 6379      

建立redis-master-service.yaml 服務, 定義開放的端口和對應的pod

apiVersion: v1
kind: Service
metadata:
  name: redis-master
  labels:
    name: redis-master
spec:
  ports:
  - port: 6379
    targetPort: 6379
  selector:
    name: redis-master      

檢視services

kubectl get services
NAME           CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
kubernetes     10.254.0.1       <none>        443/TCP    1d
redis-master   10.254.241.203   <none>        6379/TCP   3m      

由于cluster的IP是在建立pod之後由kubernetes自動配置設定的, 在其他Pod中無法預先知道某個Service的虛拟IP位址. Kubernets則使用Linux環境變量來傳達資訊. 其他的pod通過REDIS_MASTER_SERVICE_HOST 和 REDIS_MASTER_SERVICE_PORT來擷取相關資訊. 建立slave的RC

apiVersion: v1
kind: ReplicationController
metadata:
  name: redis-slave
  labels:
    name: redis-slave
spec:
  replicas: 2
  selector:
    name: redis-slave
  template:
    metadata:
      labels:
        name: redis-slave
    spec:
      containers:
      - name: master
        image: master.example.com:5000/kubeguide/guestbook-redis-slave
        env:
        - name: GET_HOSTS_FROM
          value: env
        ports:
        - containerPort: 6379      

建立redis-slave-service.yaml 服務檔案

apiVersion: v1
kind: Service
metadata:
  name: redis-slave
  labels:
    name: redis-slave
spec:
  ports:
  - port: 6379
  selector:
    name: redis-master      

建立fronted-controller.yaml

apiVersion: v1
kind: ReplicationController
metadata:
  name: frontend
  labels:
    name: frontend
spec:
  replicas: 3
  selector:
    name: frontend
  template:
    metadata:
      labels:
        name: frontend
    spec:
      containers:
      - name: frontend
        image: master.example.com:5000/kubeguide/guestbook-php-frontend
        env:
        - name: GET_HOSTS_FROM
          value: env
        ports:
          - containerPort: 80      

配置服務檔案fronted-service.yaml. type=NodePort是關鍵, 表示Node上的實體機端口提供對外通路的能力, 需要注意的是spec.ports.NodePort的端口定義由範圍限制, 預設為30000~32767,在此範圍之外則會失敗

apiVersion: v1
kind: Service
metadata:
  name: frontend
  labels:
    name: frontend
spec:
  type: NodePort
  ports:
  - port: 80
    nodePort: 30001
  selector:
    name: frontend      
tcp    LISTEN     0      128      :::30001                :::*                   users:(("kube-proxy",pid=2831,fd=9))      

系統會跟根據pod和service的關系建立相應的endpoint

kubectl get endpoints      

Kubernets 對外Service

Service的ClusterIP位址相對于Pod的IP位址來說相對穩定, Service被建立時被配置設定一個IP位址, 在銷毀該Service之前, 這個IP位址不會發生變化. Cluster IP Range池中配置設定到的IP隻能在内部被通路到, 所有其他Pod都可以無障礙的通路到它. 但是如果這個Service作為前端的服務, 則需要這個服務提供公共IP. Kubernetes提供兩種對外的Service的type定義. NodePort和LoadBalancer NodePort: 指定spec.type=NodePort, 并指定spec.ports.nodePort的值, 系統就會在Kubernetes叢集中的每個Node上打開一個主機上的真實端口号, 這樣, 能夠通路Node的用戶端都能通過這個端口号通路到内部的Service了 LoadBalancer: 如果雲服務商支援外接負載均衡器, 則可以通過spec.type=LoadBalancer定義Service. 同時需要指定負載均衡器的IP位址. status.loadBalancer.ingress.ip設定為146.148.47.155為雲服務商提供的負載均衡器的IP位址.

apiVersion: v1
kind: Service
metadata: {
  "kind": "Service",
  "apiVersion": "v1",
  "metadata": {
    "name": "my-service"
    },
  "spec":{
    "type": "LoadBalancer",
    "clusterIP": "10.0.171.239",
    "selector": {
      "app": "MyApp"
    },
    "ports": [
      {
        "protocol": "TCP",
        "port": 80,
        "targetPort": 9376,
        "nodePort": 30061,
      },
    ],
  },
  "status": {
    "loadBalancer": {
      "ingress": [
        {
          "ip": "146.148.47.155"
        },
      ]
    }
  }
}      

多端口服務

很多情況下, 一個服務都需要對外暴露多個端口号. 防止産生歧義, specports 下面可以定義名字. spec.ports.name="http"

Volume

存儲卷是Pod中能夠被多個容器通路的共享目錄. K8s中的Volume與Pod生命周期相同, 但與容器的生命周期不相關. 當容器終止或者重新開機時, volume中的資料不丢失. 1) EmptyDir: 一個EmptyDir Volume是在Pod配置設定到Node時建立的, 從它的名稱就可以看出, 它的初始内容為空. 同一個Pod下的所有容器都可以讀/寫EmptyDir中的相同檔案. 當Pod被移除後, EmptyDir中的資料也永久删除. 2) hostPath: 在Pod上挂載主控端上的檔案或目錄. 在不同的Node上具有相同配置的Pod可能會因為主控端上的目錄和檔案不同而導緻對Volume上的目錄和檔案的通路結果不一緻. 一般要使用共享存儲 以主控端/data為存儲卷

spec:
  template:
    spec:
      volumes:
      - name: "persistent-storage"
        hostPat:
          path: "/data"
      containers:
        volumeMounts:
          - name: "persistent-storage"
            mountPath: "/data"      

3) gcePersistentDisk: 使用google計算引擎上的永久磁盤. 此時要求虛拟機是GCE虛拟機 4) awsElasticBlockStore: 與GCE類似, 該volume是Amazon提供的AWS的EBS volume 5) nfs: 使用NFS提供共享目錄挂載到Pod中.

apiVersion: v1
kind: Pod
metadata:
  name: nfs-web
spec:
  containers:
    - name: web
      image: nginx
      ports:
        - name: web
          containerPort: 80
      volumeMounts:
        - name: nfs
          mountPath: "/usr/share/nginx/html"
  volumes:
    - name: nfs
      nfs:
        server: nfs-server.localhost
        path: "/"      

6) iscsi: 使用iSCSI儲存設備上的目錄挂載到Pod中 7) glusterfs 8) rbd 9) gitRepo 10) secret: 通過tmpfs實作的, 這種volume無法持久化 11) persistentVolumeClaim: 從PV(PersistentVolume)中申請所需的空間, PV通常是一種網絡存儲. 例如NFS, iSCSI, GCE, AWS等等

Namespace

kubernetes叢集在啟動後, 會建立一個名為default的Namespace

kubectl get namespaces      

預設Pod, RC, Service都将系統建立到"default"的Namespace中 使用者可以根據建立新的Namespace,

apiVersion: v1
kind: Namespace
metadata:
  name: development      

如果不加參數, kubectl get指令将顯示屬于"default" 命名空間的對象 --namespace 參數可以指定某個命名空間對象 注意: Label是有嚴格的文法規則的, 但是Annotation是可以随意定義的 Kubelet建立Pod時, 需要通過啟動一個名為google_containers/pause的鏡像來完成對Pod網絡的配置 我之前的實驗使用了将google_containers/pause鏡像下載下傳到本地的方式來實作的. 需要在每個node上進行操作, 也可以直接在kubelet的配置檔案中添加

KUBELET_ARGS="--pod_infra_container_image=master.example.com:5000/google_containers/pause:3.0"      

ETCD

etcd是高可用的key/value存儲系統, 用于持久化存儲叢集中. API Server則提供了操作etcd的封裝接口API, 以REST方式提供服務, 以REST方式提供服務.

ETCD叢集

ETCD配置叢集配置/etc/etcd/etcd.conf

[member]
ETCD_NAME=etcd1
ETCD_LISTEN_PEER_URLS="http://10.0.0.1:2380" 		#叢集内部使用的IP位址
[cluster]
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://10.0.0.1:2380" 	#廣播給叢集内其他成員的URL
ETCD_INITIAL_CLUSTER="etcd1=http://10.0.0.1:2380, etcd2=http://10.0.0.2:2380, etcd3=http://10.0.0.3:2380"
ETCD_INITIAL_CLUSTER_STATE="new"		#初始叢集狀态, new為建立叢集
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"	#叢集名稱
ETCD_ADVERTISE_CLIENT_URLS="http://10.0.0.1:2379"		#廣播給外部用戶端使用的URL      

在etcd2和etcd3加入etcd-cluster叢集的執行個體.

ETCD_INITIAL_CLUSTER_STATE="exsit"      

檢視叢集節點狀态

etcdctl cluster-health      

檢視叢集成員清單

etcdctl member list      

以kube-apiserver為例, 通路etcd叢集的參數設定為

--etcd-servers=http://10.0.0.1:4001, http://10.0.0.2:4001, http://10.0.0.3:4001      

Kubernetes 核心原理

資源對象Replication Controller簡寫為RC,而Replication Controller是指"副本控制器". 建立pod的時候最好不要越過RC直接建立Pod, 因為Replication Controller會通過RC管理Pod副本. 當Pod的重新開機政策為RestartPolicy=Always時, Replication Controller才會管理該Pod的操作(建立, 銷毀, 重新開機等) Pod執行個體都會通過RC裡定義的Pod模闆(template)建立的. selector 指定一個name, 這個name和template中的name對應 對replciationcontroller進行擴大或縮小副本數量

kubectl scale --replicas=3 replicationcontrollers foo      

ResourceQuota Controller

Kubernetes 支援三個層次的資源配額管理 1. 容器級别 2. Pod級别, 3. Namespace級别 包括的限制是Pod數量; Replication Controller數量; Service數量; ResourceQuota數量; Secret數量; PV(Persistent Volume) 數量 LimitRanger作用于Pod和Container上, ResourceQuota則作用于Namespace上

ServiceAccount Controller與Token Controller

ServiceAccount Controller與Token Controller是與安全相關的兩個控制器. Service Account Controller在Controller manager啟動時被建立.

某些特殊場景下, 例如将一個外部資料庫作為Service的後端, 或将在另一個叢集或Namespae中的服務作為服務的後端. 需要建立一個不帶标簽選擇器的Service. 如果不帶标簽選擇器, 系統不會自動建立Endpoint. 此時需要手動建立一個和該Service同名的Endpoint kube-proxy為每個Service在本地主機上開一個端口(随機選擇), 任何通路該端口的連接配接都被代理到響應的一個後端pod上.

k8s支援兩種主要的模式來找到Service. 1). 一個是容器的Service環境變量. 形如{SVCNAME}_SERVICE_HOST. 例如名稱為"redis-master"的service, 它對外暴露6379 TCP端口. 且叢集IP位址為10.0.0.11. kubelet會為建立的容器添加如下環境變量

REDIS_MASTER_SERVICE_HOST=10.0.0.11
REDIS_MASTER_SERVICE_PORT=6379
REDIS_MASTER_PORT=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP_PROTO=tcp
REDIS_MASTER_PORT_6379_TCP_PORT=6379
REDIS_MASTER_PORT_6379_TCP_ADDR=10.0.0.11      

通過環境變量來找到Service會帶來一個不好的結果, 即任何被某個pod所通路的Service, 必須先于該Pod被建立, 否則和這個後建立的Service相關的環境變量, 将不會被加入該Pod容器中.

容器健康檢查

Pod通過兩類探針來檢查容器的健康狀态, 一個是LivenessProbe探針. 另一類是使用LivenessProbe探針. LivenessProbe探針有三種實作方式1) ExecAction: 在容器中執行一個指令, 傳回值為0, 表明健康 2) TCPSocketAction: 通過容器的IP位址和端口号執行TCP檢查 3) HTTPGetAction: 通過容器IP位址和端口号以及路徑調用HTTP get方法

livenessProbe:
  exec:
  	command:
  	- cat
  	- /tmp/health
  initialDelaySeconds: 15
  timeoutSeconds: 1      
livenessProbe:
  httpGet:
  	path: /heathz
  	port: 8080
  initialDelaySeconds: 15
  timeoutSeconds: 1      

安全機制原理

Authenication認證

CA認證在API server上配置三個參數 "--client-ca-file" "--tls-cert-file" 和 "--tls-private-key-file" kuectl 的三個參數"certificate-authority" "client-certificate" 和 "client-key". 或用戶端應用的kubeconfig配置檔案中的配置項

token認證方式, 添加參數"--token_auth_file=SOMEFILE"

HTTP基本認證方式添加參數"--basic_auth_file=SOMEFILE"

Auhorization授權

在通過API通路資源之前, 必須通過通路政策進行校驗. 通路政策通過API Server的啟動參數 "--authorization_mode"配置, 該參數包含以下三個值 1) AlwaysDeny 2) AlwaysAllow 3) ABAC

ABAC表示配置使用使用者配置的授權政策去管理API Server的請求. HTTP請求包含四個能被授權程序識别的屬性 1) 使用者名 2) 是否是隻讀請求 3) 通路的屬于那一類資源, 例如Pod 4) 被通路對象所屬的Namespace 如果選用ABAC模式, 需要通過API Server的參數選項"--authorization_policy_file=SOME_FILENAME"

# 允許使用者alice做任何事情
{"user": "alice"}
# 使用者kubelet指定讀取資源Pods
{"user": "kubelet", "resource": "pods", "readonl": true} 
# 使用者Kubelet能讀和寫資源events
{"user": "kubelet", "resource": "event"}
# 使用者bob隻能讀取Namespace "myNamespace" 中的資源Pods
{"user": "bob", "resource": "pods", "readonly": true, "ns": "myNamespace"}      

Admission Control 插件

SecurityContextDeny: 禁止通過API server管理配置了下列兩項配置的pod

spec.containers.securityContext.seLinuxOptions
spec>containers.securityContext.runAsUser      

ResourceQuota: 資源配額. --adminssion_control=ResourceQuota, 使插件生效. 對資源對象的最大數量限制

{
    "apiVersion": "v1",
    "kind": "ResourceQuota",
    "metadata": {
        "name": "quota"
    },
    "spec": {
        "hard": {
            "memory": "1Gi",
            "cpu": "20",
            "pods": "10",
            "services": "5",
            "replicationcontrollers": "20",
            "resourcequotas": "1"
        }
    }
}      

LimitRanger: 用于列舉Namespace中各資源的最小限制, 最大限制和預設值. --adminssion_control=LimitRanger

apiVersion: v1
kind: LimitRange
metadata:
  name: myLimits
spec:
  limits:
  - max:
      cpu: "2"
      memory: 1Gi
    min:
      cpu: 250m
      memory: 6Mi
    type: Pod
  - default:
      cpu: 250m
      memory: 100Mi
    max:
      cpu: "2"
      memory: 1Gi
    min:
      cpu: 250m
      memory: 6Mi
    type: Container      

Secret: 私密憑據 登入私有Registry, 第一次登入會建立私有的使用者名密碼, 相關資訊将會寫入~/.dockercfg檔案中

docker login localhost:5000      

Service Account: 多個Secret的集合

kubectl get serviceAccounts      

叢集安全配置案例

雙向認證配置

雙向認證配置: 1) 生成根證書, API server服務端證書, 伺服器端私鑰, 各元件所用的用戶端證書和用戶端私鑰 2) 修改k8s各個服務程序的啟動參數, 啟動雙向認證模式 證書目錄/var/run/kubernetes 産生私鑰

openssl genrsa -out dd_ca.key 2048      

生成根證書(自簽證書)

openssl req -x509 -new -nodes -key dd_ca.key -subj "/CN=example.com" -days 5000 -out dd_ca.crt      

生成API Server的服務端證書和私鑰

openssl genrsa -out dd_server.key 2048
openssl req -new -key dd_server.key -subj "/CN=master.example.com" -out dd_server.csr
openssl x509 -req -in dd_server.csr -CA dd_ca.crt -CAkey dd_ca.key -CAcreateserial -out dd_server.crt -days 5000      

生成Controller Manager與Scheduler程序公用的證書和私鑰

openssl genrsa -out dd_cs_client.key 2048
openssl req -new -key dd_cs_client.key -subj "/CN=master.example.com" -out dd_cs_client.csr
openssl x509 -req -in dd_cs_client.csr -CA dd_ca.crt -CAkey dd_ca.key -CAcreateserial -out dd_cs_client.crt -days 5000      

生成Kubelet所用的用戶端證書和私鑰, 假設NodeIP位址為192.168.48.142

openssl genrsa -out dd_kubelet_client.key 2048
openssl req -new -key dd_kubelet_client.key -subj "/CN=192.168.48.142" -out dd_kubelet_client.csr
openssl x509 -req -in dd_kubelet_client.csr -CA dd_ca.crt -CAkey dd_ca.key -CAcreateserial -out dd_kubelet_client.crt -days 5000      

修改API Server的啟動參數/etc/kubernetes/apiserver 并重新開機apiserver

KUBE_API_ARGS="--log-dir=/var/log/kubernetes --secure-port=443 --client_ca_file=/home/cert/dd_ca.crt --tls-private-key-file=/home/cert/dd_server.key --tls-cert-file=/home/cert/dd_server.crt"      

驗證api server

curl https://master.example.com:443/api/v1/nodes --cert dd_cs_client.crt --key dd_cs_client.key --cacert dd_ca.crt      

修改Controller Manager的啟動參數

KUBE_CONTROLLER_MANAGER_ARGS="--log-dir=/var/log/kubernetes --service_account_private_key_file=/home/cert/dd_cs_client.key --root-ca-file=/home/cert/dd_ca.crt --master=https://master.example.com:443 --kubeconfig=/etc/kubernetes/cmkubeconfig"      

建立/etc/kubernetes/cmkubeconfig檔案, 配置證書相關參數并且重新開機kube-controller-manager服務

apiVersion: v1
kind: Config
users:
- name: controllermanager
  user:
    client-certificate: /home/cert/dd_cs_client.crt
    client-key: /home/cert/dd_cs_client.key
clusters:
- name: local
  cluster:
    certificate-authority: /home/cert/dd_ca.crt
contexts:
- context:
    cluster: local
    user: controllermanager
  name: my-context
current-context: my-context      

在每個Node上建立/var/lib/kubelet/kubeconfig檔案.

apiVersion: v1
kind: Config
users:
- name: kubelet
  user:
    client-certificate: /home/dd_kubelet_client.crt
    client-key: /home/dd_kubelet_client.key
clusters:
- name: local
  cluster:
    certificate-authority: /home/dd_ca.crt
contexts:
- context:
    cluster: local
    user: kubelet
  name: my-context
current-context: my-context      

修改Kubelet的啟動參數, 以修改/etc/kubernetes/kubelet配置檔案為例

KUBELET_API_SERVER="--api_servers=https://master.example.com:443"
KUBELET_ARGS="--kubeconfig=/var/lib/kubelet/kubeconfig"      

配置kube-proxy, 建立/var/lib/kubeproxy/proxykubeconfig

apiVersion: v1
kind: Config
users:
- name: kubeproxy
  user:
    client-certificate: /home/dd_kubelet_client.crt
    client-key: /home/dd_kubelet_client.key
clusters:
  - name: local
    cluster:
      certificate-authority: /home/dd_ca.crt
contexts:
  - context:
      cluster: local
      user: kubeproxy
    name: my-context
current-context: my-context      

配置/etc/kubernetes/proxy并重新開機kube-proxy

KUBE_PROXY_ARGS="--kubeconfig=/var/lib/kubeproxy/proxykubeconfig --master=https://master.example.com:443"      

簡單認證配置

建立使用者名密碼和UID的檔案/root/token_auth_file

thomas, thomas, 1
admin, admin, 2      

修改API Server的配置, 重新開機apiserver

KUBE_API_ARGS="--secure-port=443 --token_auth_file=/root/token_auth_file"      

使用curl驗證API server

curl https://master.example.com:443/version -H "Authorization: Bearer thomas" -k      

HTTP base認證

建立使用者名密碼和UID的檔案/root/token_auth_file

thomas, thomas, 1
admin, admin, 2      

修改API Server的配置, 重新開機APIserver

KUBE_API_ARGS="--secure-port=443 --basic_auth_file=/root/basic_auth_file"      

用curl驗證連接配接API Server

curl https://master.example.com:443/version --basic -u thomas:thomas -k      

Kuberntes 網絡原理

每個Pod都有一個獨立的IP位址, 所有的Pod都在一個可以直接連通的, 扁平的網絡空間中. 不論這些pod是否在同一個主控端中, 都要求它們可以直接通過對方的IP進行通路. 這種模式稱為IP per Pod模型 在同一個pod中的容器可以通過localhost來連接配接其他容器的端口.

Linux網絡棧中引入了網絡命名空間(Network Namespace), 這些獨立的協定棧被隔離到不同的命名空間中. 彼此間無法通信. Linux的網絡命名空間内可以有自己的路由表及獨立的Iptables/Netfilter來設定提供包轉發, NAT及IP包過濾等功能. 讓處在不同命名空間的網絡互相通信, 甚至和外部的網絡進行通信, 可以使用Veth裝置對. 它就像一個管道, 一端連着一個網絡命名空間的協定棧, 一端連着另一個網絡命名空間的協定棧. 建立一個網絡命名空間

ip netns add <name>      

檢視命名空間中的内容

ip netns exec <name> ip addr show      

如果要執行多個指令, 可以先進入命名空間的bash, 使用exit退出命名空間

ip netns exec <name> bash       

veth裝置屬于可以轉移的裝置, 即可以在不同命名空間中轉換. 但是很多其他裝置例如lo裝置, vxlan裝置, ppp裝置, bridge裝置等都是不可以轉移的.

ip link set veth1 netns ns1      

檢視是否可以進行轉移, 為on則意味着不可以進行轉移

ethtool -k docker0|grep netns
netns-local: on [fixed]      

veth對, 總是以成對的方式出現的. 兩端稱為peer 建立Veth裝置對:

ip link add veth0 type veth peer name veth1      

将veth1遷移到netns ying中

ip link set veth1 netns ying      

為veth0/veth1建立ip位址

ip netns exec ying ip addr add 10.1.1.1/24 dev veth1
ip addr add 10.1.1.2/24 dev veth0      

啟動veth0/veth1

ip link set veth0 up
ip netns exec ying ip link set dev veth1 up      

此時兩個veth peer就可以彼此通信了. 可以使用ethtool來檢視veth對的peer

ethtool -S veth0      

網橋

預設MAC位址的過期時間是5min. Linux的網橋提供了這些裝置之間互相轉發資料的二層裝置. 于switch純二層裝置不同, 運作着linux核心的機器本身就是一台主機, 有可能是網絡封包的目的地. 其收到的封包除了轉發和丢棄, 還可能被送到網絡協定棧的上層(網絡層), 進而被這台主機的協定棧消化. 是以此時, 網橋即是二層裝置也是一個三層裝置.

Linux核心是通過一個虛拟的網橋裝置(Net Device)來實作網橋的. Net Device與一般的裝置不同, 最明顯的一個特征是它還可以有自己的一個IP位址.

例如一個br0橋接了兩個網卡, eth0, eth1. 對于上層協定棧而言, 隻看得到br0, 上層協定棧将封包發送給br0, 網橋裝置的處理代碼判斷封包該發送給eth0還是eth1. 反過來eth0/1接收到的封包被送出給網橋處理代碼.

Iptables/Netfilter

Linux網絡協定棧中有一組回調函數挂節點. hook鈎子函數. Netfilter負責在核心執行各種挂接的規則, 運作在核心模式中. 而iptables是在使用者模式下運作的程序, 負責協助維護核心中的Netfilter的各種規則表.

路由

Linux路由表至少包含兩個表, 當啟用政策路由的時候還會有其他表. 一個是LOCAL一個是MAIN. LOCAL表中包含所有本地裝置位址. LOCAL表示在建立網絡裝置的時候自動建立的, LOCAL表用于供Linux協定棧識别本地位址, 以及進行本地各個不同網絡接口之間的資料轉發. 檢視local表

ip route show table local type local      

MAIN表用于各類網絡IP位址的轉發, 它的建立既可以使用靜态配置生成, 也可以使用動态路由發現協定生成. 動态路由發現協定是使用一組多點傳播功能來發送路由發現資料, 動态交換和擷取網絡的路由資訊, 并更新到路由表中. Linux下支援路由發現協定的開源軟體有很多, 常用的有Quagga, Zebra等. 路由表檢視

ip route list      

Docker的網絡實作

标準的Docker支援一下四類網絡模式 host模式: 使用 --net=host指定 container模式: 使用 --net=container: NAME_or_ID指定 none模式: 使用 --net=none指定 bridge模式: 使用 --net=bridge指定

Kubernets管理模式下, 通常隻會使用bridge模式. bridge模式下, 會建立一個docker0的網橋, 然後私有網絡空間會給這個網橋設定一個子網. 每一個被建立出來的容器, 都會建立一個虛拟的以太網裝置(veth對), 另一端使用Linux的網絡命名空間技術, 映射到容器内的eth0裝置, 然後從網橋的位址段内給eth0接口配置設定一個IP位址. 這樣做的結果是, 同一個主機上的容器可以彼此通信, 通過IP位址. 但是不同主機上的容器就必須使用port來實作.然後通過這個端口路由或代理到容器上. docker的iptables在nat表中. 前兩條是架構, 生效時都會走DOCKER鍊. NAT第三條的含義是, 若本地發出的資料包不是通往docker0接口時, 即發往主機之外的裝置時, 都需要進行動态位址修改MASQUERADE

-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE      

filter表中, 第二條如果接收到的資料包屬于以前已經建立好的連接配接, 那麼允許直接通過. 這樣接受到的資料包自然又走回docker0, 并中專到響應的容器.

-A FORWARD -j DOCKER-ISOLATION
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT      

建立registry容器後, 自動添加一條路由規則

-A POSTROUTING -s 172.17.0.2/32 -d 172.17.0.2/32 -p tcp -m tcp --dport 5000 -j MASQUERADE
-A DOCKER -d 172.17.0.2/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 5000 -j ACCEPT      

Kubernetes的網絡實作

1) 緊密耦合的容器到容器之間的直接通信 同一個pod内的容器共享同一個網絡命名空間, 共享同一個Linux協定棧. 容器之間可以用localhost位址通路彼此的端口. 可以直接使用本地IPC進行通信.

2) 抽象的Pod到Pod之間的通信 同一個Node内的Pod之間的通信, 本身兩個pod都是在docker0網段内的IP位址. 直接通過docker0網橋進行中轉即可. 不同Node上的Pod之間的通信. k8s對docker0的IP位址進行規劃, 保證每一個Node上的docker0位址沒有沖突. k8s的網絡增強開源軟體Flunnel就能夠管理資源池的配置設定. 在GCE環境下, 路由打通是通過GCE來完成的. 在私有雲環境中, 需要額外的網絡配置.

3) Pod到Service之間的通信 Service是對一組Pod的抽象. 将Service落實的是kube-proxy服務程序. 這個程序可以看做Service的透明代理兼. kube-proxy都會在本地Node上建立一個SocketServer來負責接收請求, 然後均勻發送到後端某個Pod的端口上, 這個過程使用Round Robin負載均衡算法. Services的ClusterIP與NodePort等概念是kube-porxy通過iptables的NAT轉換實作的. 通路Service的請求, 不論是cluster IP + TargetPort 的方式, 還是使用節點機 Node IP + NodePort的方式, 都被節點機的iptables規則重定向到kube-proxy監聽服務代理端口. 目前kube-proxy隻支援RR和會話保持(如果Service中定義了會話親和性) SocketServer: 端口是随機選擇的一個本地空閑端口 kube-proxy在啟動和監聽到Service或Endpoint的變化後, 會在本機iptables的NAT表中添加4條規則鍊. KUBE-PORTALS-CONTAINER: 從容器中通過Service Cluster IP和端口号通路Service請求 KUBE-PORTALS-HOST: 從主機中通過Service Cluster IP 和端口号通路Service請求 KUBE-NODEPORT-CONTAINER: 從容器中通過Service的NodePort端口号通路Service的請求 KUBE-NODEPORT-HOST: 從容器中通過Service的NodePort端口号通路Service的請求

4) 叢集外部與内部元件之間的通信 Pod被外部通路, 通過NodePort在Node節點上打開一個對外的端口. LoadBalancer.

開源的網絡元件

直接路由

可以使用靜态路由的方式, 但是靜态路由需要每台節點都進行配置. 在每個Node的路由表中添加到對方docker0的路由轉發規則配置項. eg. Pod1 docker0 IP子網為10.1.10.0, Node位址為192.168.1.128; Pod2 所在docker0網橋的IP子網是10.1.20.0, Node位址為192.168.1.129 在Node1上用route add指令添加一條到Node2上docker0的靜态路由規則

route add -net 10.1.20.0 netmask 255.255.255.0 gw 192.168.1.129      

同樣, 在Node2上添加一條到Node1上docker0的靜态路由規則

route add -net 10.1.10.0 netmask 255.255.255.0 gw 192.168.1.128      

使用這種方式, 要保證每台node的docker網段不能重疊. 如果使用在大規模場景中, 則需要添加數以百計的靜态路由. 可以借助動态路由發現協定工具Quagga軟體來實作.

docker pull index.alauda.cn/georce/router      

Quagga容器啟動時需要以--privileged特權模式運作, 并且指定--net-host, 表示直接使用實體機的網路

docker run -itd --name-router --privileged --net=host index.alauda.cn/georce/router      

過段時間後就會自動添加路由規則

Flannel

它可以協助k8s, 給每一個Node上的Docker容器配置設定互相不沖突的IP位址. 能在這些IP位址之間建立一個疊加網絡. Flannel建立一個flannel0的網橋, 而且這個網橋一端連接配接docker0網橋, 另一端連接配接flanneld的服務程序. flanneld程序首先連接配接etcd, 利用etcd來管理可配置設定的IP位址段資源. 同時監控etcd中的每個Pod的實際位址, 并在記憶體中建立一個Pod節點路由表. 然後下連docker0和實體網絡, 使用記憶體中的Pod節點路由表, 将docker0發給它的資料包包裝起來, 利用實體網絡的連接配接将資料包投遞到目标flanneld上, 進而完成pod到pod的直接通信. Flannel使用了集中的etcd存儲, 集中配置設定和處理IP, 就不會産生沖突. Flannel通過修改docker的啟動參數将配置設定給它的位址段傳遞進去 --bip. 但是Flannel模型預設地使用了UDP作為底層傳輸協定, UDP本身并不可靠.

安裝flannel

下載下傳位址 https://github.com/coreos/flannel/releases 将下載下傳的壓縮包解壓, 把二進制檔案flanneld和mk-docker-opts.sh複制到/usr/bin, 既完成了對flannel的安裝 編輯服務配置檔案/usr/lib/systemd/system/flanneld.service

[Unit]
Description=Flanneld overlay address etcd agent 
After=network.target
Before=docker.service
[Service]
Type=notify
EnvironmentFile=/etc/sysconfig/flanneld
EnviornmentFile=-/etc/sysconfig/docker-network
ExecStart=/usr/bin/flanneld -etcd-endpoints=${FLANNEL_ETCD} $FLANNEL_OPTIONS
[Install]
RequiredBy=docker.service
WantedBy=multi-user.target      

編輯檔案/etc/sysconfig/flannel,

FLANNEL_ETCD="http://192.168.48.141:4001"
FLANNEL_ETCD_KEY="/atomic.io/network"      

在啟動flannel之前, 需要在etcd中添加一條網絡配置記錄, 這個配置将用于flannel配置設定給每個Docker的虛拟IP位址段

etcdctl set /atomic.io/network/config '{"Network": "10.1.0.0/16"}'      

flannel将覆寫docker0網橋, 是以要先停止docker服務. 啟動flanneld服務 在每個Node節點上執行以下指令來完成對docker0網橋的配置

/usr/libexec/flannel/mk-docker-opts.sh -i
source /run/flannel/subnet.env
ifconfig docker0 ${FLANNEL_SUBNET}      

這樣便完成flanne疊加網絡的設定

Open vSwitch

Open vSwitch的網橋可以直接建立多種通信通道. 例如GRE/VxLAN. 當容器内的應用通路另一個容器的位址時, 資料包會通過容器内的預設路由發送給docker0網橋. ovs的網橋作為docker0網橋的端口存在, 它會将資料發送給ovs網橋. ovs網絡已經通過配置建立了和其他ovs網橋和GRE/VxLAN隧道, 自然能夠将資料送達對端的Node 正常啟動Open Vswitch後, 會啟動兩個程序: ovsdb-server與ovs-vswitchd 建立網橋和GRE隧道: 在每個Node上建立ovs的網橋br0, 然後在網橋上建立一個GRE隧道連接配接對端網橋, 最後把ovs的網橋br0作為一個端口連接配接到docker0這個linux網橋上(可以了解為交換機互聯). 如此一來, 兩個節點機器上的docker0網段就能互通了. 建立ovs網橋

ovs-vsctl add-br br0      

建立GRE隧道連接配接對端, remote_ip為對端eth0的網卡位址. remote_ip要設定為對端的IP位址

ovs-vsctl add-port br0 gre1 -- set interface gre1 type=gre option:remote_ip=192.168.18.128      

添加br0到本地docker0, 使得容器流量通過OVS流經tunnel

brctl addif docker0 br0      

啟動br0與docker0網橋

ip link set dev br0 up
ip link set dev docker0 up      

添加路由規則, 由于兩台Node的docker0網段分别為172.17.43.0/24與172.17.42.0/24, 這兩個網段的路由都要經過本機的docker0網橋路由. 需要在每個Node上添加通過docker0網橋轉發的172.17.0.0/16端的路由規則. 相當于設定一個大的路由網段涵蓋所有Node節點

ip route add 172.17.0.0/16 dev docker0      

ping test需要, 清空docker自帶iptables規則

iptables -t nat -F; iptables -F      

這種網絡架構的缺點非常明顯, N個Node需要建立N*(N-1)條GRE隧道

k8s網絡案例

在k8s上啟動一個容器時, 會先啟動google_containers/pause這個容器, 其他pod中的容器都會關聯到這個容器上. 這個pause的容器執行端口映射規則, 這樣就可以簡化端口映射的過程. 使用docker port可以檢視端口映射

docker port <container>      

添加service之後, 所有通往以及從cluster IP出來的流量都被指向kube-proxy的某個随機端口(如果沒有設定端口映射) kube-proxy作為一個全功能的代理伺服器管理了兩個獨立的TCP連接配接: 一個是從容器到kube-proxy,另一個是kube-proxy到負載均衡的目标pod.

K8s開發指南

傳統的Web應用大多是B/S架構, 涉及如下規範. 1) 客戶-伺服器, 這種規範的提出, 改善了使用者接口跨多個平台的可移植性. 分離的使用者接口和資料存儲.使得不同的使用者共享相同的資料成為可能 2) 無狀态性: 每次request必須包含所有的資訊, 可見性: 服務端和用戶端不需要了解request的曆史. 可靠性: 減少了伺服器從局部錯誤中恢複的任務量. 可伸縮性: 可以很容易的釋放資源(無需會話保持). 無狀态性會增加每次單獨請求的開銷 3) 緩存: 用戶端緩存response資料的功能, 這樣就可以為以後的request公用緩存資料. 但是可能會導緻伺服器與用戶端的資料不一緻性.

在傳統的B/S架構下, REST提供了統一接口, 分層系統和按需代碼. 1) 統一接口: 在REST世界中, 所有的事務都被抽象為資源. REST通過通用的連結器接口對資源進行操作, 極大的解耦. 2) 分層系統: 各分層系統提高了各種層次之間的獨立性. 為系統複雜度提供邊界. 3) 按需代碼: 允許對用戶端功能進行擴充.

REST提出了一下的設計準則 1) 網絡上的所有事物都被抽象為資源(Resource) 2) 每個資源對應一個唯一的資源辨別符(Resource Identifier) 3) 通過通用的連結器接口(Generic Connector Interface)對資源進行操作 4) 對資源的各種操作不會改變資源辨別符 5) 所有的操作都是無狀态的(Stateless)

API

GET: 擷取某一類型的資源清單 POST: 建立一個資源 GET: 獲得單個資源 DELETE: 删除單個資源 PUT: 更新或建立資源 PATCH: 選擇修改資源詳細指定的域

K8s運維管理

Node的隔離:

在kind:node 下添加spec: unschedulable: true

kubectl replace -f unschedule_node.yaml      

Node的擴容:

新的Node完成安裝後向Master注冊即可

Pod動态擴容和縮放

可以使用scale rc的方式來進行操作

kubectl scale rc redis-slave --replicas=3      

更新資源對象的Label

可以直接使用kubectl的label指令

kubectl label pod redis-master-bobr0 role=backend      

檢視響應的Label

kubectl get pods -Lrole      

删除一個Label隻需要在label後加一個減号即可

kubectl label pod redis-master-bobr0 role-      

修改一個Label的值, 需要加上--overwrite參數:

kubectl label pod redis-master-bobr0 role=master --overwrite      

将Pod排程到指定Node上

首先給Node打一個特定的标簽

kubectl label nodes <node-name> <label-key>=<label-value>
kubectl label nodes node1 zone=north      

在spec.template.spec.nodeSelector.zone: north 然後使用create -f 建立 node 然後檢視node的分布狀态

kubectl get pods -o wide      

滾動更新

使用rolling-update指令, 建立一個新的RC, 然後自動控制舊的RC中的Pod副本數量逐漸減少到0.但是新舊的RC必須處在同一個Namespace中.

kubectl rolling-update redis-master -f redis-master-controller-v2.yaml      

或者也可以直接指定鏡像源進行滾動更新

kubectl rolling-update redis-master --image=redis-master:2.0      

如果更新過程中發現配置有誤, 可以終端操作, 并使用--rollback選項進行復原

kubectl rolling-update redis-master --image=kubeguide/redis-master:2.0 --rollback      

Kubernetes的高可用方案

etcd要配置叢集參考etcd的配置部分

Kubernetes Master元件的高可用方案

至少使用三台伺服器安裝Master服務, 并且使用Active-Standby-Standby模式, 保證任何時候總有一套Master能夠正常工作. 可以使用pacemaker等工具來實作.

k8s資源配額管理

--adminssion_control=LimiRanger, ResourceQuota spec.template.spec.name.resources.limits.cpu:0.5 spec.template.spec.name.resources.limits.memory: 128Mi cpu的0.5也可以寫成500m. k8s啟動一個容器時, 會将CPU的配置值乘以1024并轉為整數傳遞給docker run的--cpu-shares參數, 之是以乘以1024是因為Docker的cpu-shares參數是以1024為技術計算CPU時間的. 這個計數僅僅是一個權重, 使用cpu時間等于權重*(所有容器權重和) 再乘以CPU核心數.

apiVersion: v1
kind: LimitRange
metadata:
  name: limit-range-1
spec:
  limits:
    - type: "Pod"
      max:
        cpu: "2"
        memory: 1Gi
      min:
        cpu: 250m
        memory: 32Mi
    - type: "Container"
      max:
        cpu: "2"
        memory: 1Gi
      min:
        cpu: 250m
        memory: 32Mi
      default:
        cpu: 250m
        memory: 64Mi      

檢視限額配置

kubectl describe limits      

使用ResourceQuota可以實作基于租戶的配額管理. 不同租戶使用不同的命名空間 建立命名空間

apiVersion: v1
kind: Namespace
metadata:
  name: development      

建立ResourceQuota配額配置

apiVersion: v1
kind: ResourceQuota
metadata:
  name: quota-development
  namespace: development
spec:
  hard:
    cpu: "32"
    memory: 256Gi
    persistentvolumeclaims: "10"
    pods: "100"
    replicationcontrollers: "50"
    resourcequotas: "1"
    secrets: "20"
    services: "50"      

檢視ResourceQuota的詳細資訊

kubectl describe quota quota-development --namespace=development      

可以了解為ResouceQuota是對總額的限定, Limitrange是對個别機關的限定

K8s監控

cAdvisor

開源軟體cAdvisor用于監控容器運作狀态的利器. 預設已經安裝在kubelet元件中了, kubelet的啟動參數 --cadviosr-port定義了cAdvisor對外提供服務的端口号, 預設為4194 cAdvisor也可以使用api來擷取主機的相關資訊 http://master.example.com:4194/api/v1.3/machine 傳回一個json檔案 檢視容器節點上最近一分鐘内的性能資料

http://192.168.48.142:4194/api/v1.3/subcontainers/system.slice/docker-443bcc6793b26150bffd8ab00ac803309f0581b8470c7214763e10b40c08350f.scope      

容器日志

可以檢視資源的event日志. 使用kubectl describe pods 可以看到event資訊, 對于troubleshooting非常有效 檢視日志内容可以使用kubectl logs

kubectl logs <pod_name>
kubectl logs <pod_name> -c <container_name>      

相當于容器的指令

docker logs <container_id>      

檢視kubernetes的系統日志

journalctl -u kube-controller-manager      

單獨指定日志存放目錄: --log-dir=/var/log/kubernetes

K8s社群

https://github.com/GoogleCloudPlatform/kubernetes/wiki/User-FAQ https://github.com/GoogleCloudPlatform/kubernetes/wiki/Debugging-FAQ

kubernetes DNS服務配置

Pod在通路其他Service時, 可以通過兩種服務發現方式來完成, 即環境變量和DNS的方式. 使用環境變量是有限制條件的, 即Service必須在Pod之前被建立出來, 然後系統才能在建立的Pod中自動設定與Service相關的環境變量. DNS則沒有這個限制

K8s提供的DNS由以下三個元件組成 1) etcd: DNS存儲 2) kube2sky: 将Kubernetes Master中的Service注冊到etcd 3) skyDNS: 提供DNS域名解析服務 這三個元件都可以以Pod的方式啟動和運作, 在K8s叢集中需要将各個Pod之間的網絡打通. 建立skydns-rc2.yaml

apiVersion: v1
kind: ReplicationController
metadata:
  name: kube-dns-v6
  namespace: default
  labels:
    k8s-app: kube-dns
    version: v6
    kubernetes.io/cluster-service: "true"
spec:
  replicas: 1
  selector:
    k8s-app: kube-dns
    version: v6
  template:
    metadata:
      labels:
        k8s-app: kube-dns
        version: v6
        kubernetes.io/cluster-service: "true"
    spec:
      containers:
      - name: etcd
        image: gcr.io/google_containers/etcd:2.0.9
        command:
        - /usr/local/bin/etcd
        - -listen-client-urls
        - http://0.0.0.0:2379,http://0.0.0.0:4001
        - -advertise-client-urls
        - http://127.0.0.1:2379,http://127.0.0.1:4001
        - -initial-cluster-token
        - skydns-etcd
      - name: kube2sky
        image: gcr.io/google_containers/kube2sky:1.11
        resources:
          limits:
            cpu: 100m
            memory: 50Mi
        command:
        - /kube2sky
        - --kube_master_url=http://10.8.65.48:8080
        - -domain=kube.local
      - name: skydns
        image: gcr.io/google_containers/skydns:2015-03-11-001
        resources:
        command:
        - /skydns
        - -machines=http://localhost:4001
        - -addr=0.0.0.0:53
        - -domain=kube.local.
        ports:
        - containerPort: 53
          name: dns
          protocol: UDP
        - containerPort: 53
          name: dns-tcp
          protocol: TCP
      dnsPolicy: Default      

建立skydns-svc.yaml

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

啟動DNSserver的cluster啟動ip是10.254.0.10 修改每台Node上Kubelet的啟動參數 --cluster_dns=10.254.0.10 --cluster_domain=cluster.local

kube2sky容器應用通過調用kubernetes master的API獲得叢集中所有Service的資訊, 并持續監控新Service的生成. 然後寫入etcd中

kubectl exec kube-dns-v6-5tpm2 -c etcd --namespace=default etcdctl ls /skydns/kube/local      

在域名下kube.local的域名下可以檢視各服務對應的鍵值, 可以看到完整的域名解析redis-master.default.kube.local

kubectl exec kube-dns-v6-5tpm2 -c etcd --namespace=kube-system etcdctl get /skydns/local/kube/local/default/redis-master      

在每個Pod中的/etc/resolv.conf檔案中添加了DNS域名解析

nameserver 10.254.0.10
search default.svc.kube.local svc.kube.local kube.local localdomain      

test

posted on 2017-03-22 07:51  孫大喜 閱讀( ...) 評論( ...) 編輯 收藏

轉載于:https://www.cnblogs.com/sundaxi/p/6597847.html