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服務配置testphp
Subversion 官網html
http://subversion.tigris.org/前端
案例新浪雲SAE openshift自己是一種套件java
技術 | 描述 |
---|---|
Kubernutes | 管理容器的組件; 集羣管理 %80內容 |
Apache | 對外接口服務, 以及帳號的管理 |
Git | 代碼的管理, svn |
Etd | 非關係型數據庫 |
docker | 容器 hub.docker.com 國內的docker倉庫, 時速雲 hub.tenxcloud.com 阿里雲的docker |
默認密碼是Asimovnode
隔離namespace的定義python
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/mysql
Docker被稱爲第三代Pass平臺 DotCloud, 主要基於Pass平臺爲開發者.linux
Docker的核心技術cgroups. 將一組程序定義爲一個group, 在這個group中, 有分配好的特定比例的cpu時間, io時間, 可用內存大小等. 最先是由google工程師提出. cgroups的重要概念是"子系統", 也就是資源控制器, 每一個子系統就是一個資源的分配器. 好比CPU子系統是控制CPU時間分配的. 首先須要掛載子系統, 而後纔有control group. 筆記: http://blog.opskumu.com/docker.htmlios
LXC是linux containers的簡稱, 是一種基於容器的操做系統層級的虛擬化技術. 藉助於namespace的隔離機制和cgroup限額功能, LXC提供了一套統一的API和工具來創建和管理容器. Namespace: 命名空間, 至關於平行宇宙, 每一個命名空間相互隔離, 互不干擾 LXC: 提供一個共享kernel的OS級別的虛擬化方法, 在執行時不用重複加載kernel, 因爲共享kernel, 會致使一些kernel參數沒辦法在某個特定容器內進行修改. AUFS: docker的文件系統, 是一個能透明覆蓋一或多個現有文件系統的層狀文件系統. 支持將不一樣目錄掛載到同一個虛擬文件系統下, 能夠把不一樣的目錄聯合在一塊兒, 組成一個單一的目錄. 這是一種虛擬的文件系統, 文件系統不須要格式化, 直接掛載便可. 支持寫入復刻(copy on write). 差別存儲, 最大化公用底層的文件系統. 容器不建議使用sshd服務. docker exec命令能夠進入容器排查問題.nginx
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]
配置文件爲/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
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
建立本地的鏡像倉庫
建立鏡像的方法有三種, 基於已有鏡像建立, 基於本地模板導入以及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 "ying.sun@example.com" 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的架構
/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
容器間基於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的概念, 還在繼續的發展中.
平行宇宙. 在不一樣虛擬機中的網卡彼此是不可見的, 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
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
Registry包含一個或多個Repository Repository包含一個或多個Image. Image使用GUID表示, 有一個或多個Tag與之關聯
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) 基金會
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上的存儲卷.
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.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/
測試鏡像文件在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
建立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
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"
存儲卷是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等等
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是高可用的key/value存儲系統, 用於持久化存儲集羣中. API Server則提供了操做etcd的封裝接口API, 以REST方式提供服務, 以REST方式提供服務.
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
資源對象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
Kubernetes 支持三個層次的資源配額管理 1. 容器級別 2. Pod級別, 3. Namespace級別 包括的限制是Pod數量; Replication Controller數量; Service數量; ResourceQuota數量; Secret數量; PV(Persistent Volume) 數量 LimitRanger做用於Pod和Container上, ResourceQuota則做用於Namespace上
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
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"
在經過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"}
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
建立用戶名密碼和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
每一個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接收到的報文被提交給網橋處理代碼.
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支持一下四類網絡模式 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
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
過段時間後就會自動添加路由規則
它能夠協助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自己並不可靠.
下載地址 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的網橋能夠直接創建多種通訊通道. 例如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上啓動一個容器時, 會先啓動google_containers/pause這個容器, 其餘pod中的容器都會關聯到這個容器上. 這個pause的容器執行端口映射規則, 這樣就能夠簡化端口映射的過程. 使用docker port能夠查看端口映射
docker port <container>
添加service以後, 全部通往以及從cluster IP出來的流量都被指向kube-proxy的某個隨機端口(若是沒有設置端口映射) kube-proxy做爲一個全功能的代理服務器管理了兩個獨立的TCP鏈接: 一個是從容器到kube-proxy,另外一個是kube-proxy到負載均衡的目標pod.
傳統的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)
GET: 獲取某一類型的資源列表 POST: 建立一個資源 GET: 得到單個資源 DELETE: 刪除單個資源 PUT: 更新或建立資源 PATCH: 選擇修改資源詳細指定的域
在kind:node 下添加spec: unschedulable: true
kubectl replace -f unschedule_node.yaml
新的Node完成安裝後向Master註冊便可
可使用scale rc的方式來進行操做
kubectl scale rc redis-slave --replicas=3
能夠直接使用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
首先給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
etcd要配置集羣參考etcd的配置部分
至少使用三臺服務器安裝Master服務, 而且使用Active-Standby-Standby模式, 保證任什麼時候候總有一套Master可以正常工做. 可使用pacemaker等工具來實現.
--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是對個別單位的限定
開源軟件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
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