Kubernetes是一個開源的,用於管理雲平臺中多個主機上的容器化的應用,Kubernetes的目標是讓部署容器化的應用簡單而且高效(powerful),Kubernetes提供了應用部署,規劃,更新,維護的一種機制。javascript
Kubernetes一個核心的特色就是可以自主的管理容器來保證雲平臺中的容器按照用戶的指望狀態運行着(好比用戶想讓apache一直運行,用戶不須要關心怎麼去作,Kubernetes會自動去監控,而後去重啓,新建,總之,讓apache一直提供服務),管理員能夠加載一個微型服務,讓規劃器來找到合適的位置,同時,Kubernetes也系統提高工具以及人性化方面,讓用戶可以方便的部署本身的應用(就像canary deployments)。css
Kubernetes節點有運行應用容器必備的服務,而這些都是受Master的控制。
每次個節點上固然都要運行Docker。Docker來負責全部具體的映像下載和容器運行。html
Kubernetes主要由如下幾個核心組件組成:前端
除了核心組件,還有一些推薦的Add-ons:java
在Kubernetes中,最小的管理元素不是一個個獨立的容器,而是Pod,Pod是最小的,管理,建立,計劃的最小單元.一個Pod(就像一羣鯨魚,或者一個豌豆夾)至關於一個共享context的配置組,在同一個context下,應用可能還會有獨立的cgroup隔離機制,一個Pod是一個容器環境下的「邏輯主機」,它可能包含一個或者多個緊密相連的應用,這些應用多是在同一個物理主機或虛擬機上。node
- 同一個Pod中的應用能夠共享磁盤
- 因爲docker的架構,一個Pod是由多個相關的而且共享磁盤的容器組成
標籤其實就一對 key/value ,被關聯到對象上,好比Pod,標籤的使用咱們傾向於可以標示對象的特殊特色,而且對用戶而言是有意義的(就是一眼就看出了這個Pod是尼瑪數據庫),可是標籤對內核系統是沒有直接意義的。標籤能夠用來劃分特定組的對象(好比,全部女的),標籤能夠在建立一個對象的時候直接給與,也能夠在後期隨時修改,每個對象能夠擁有多個標籤,可是,key值必須是惟一的mysql
Namespace是對一組資源和對象的抽象集合,好比能夠用來將系統內部的對象劃分爲不一樣的項目組或用戶組。常見的pods, services, replication controllers和deployments等都是屬於某一個namespace的(默認是default),而node, persistentVolumes等則不屬於任何namespacelinux
Replication Controller 保證了在全部時間內,都有特定數量的Pod副本正在運行,若是太多了,Replication Controller就殺死幾個,若是太少了,Replication Controller會新建幾個,和直接建立的pod不一樣的是,Replication Controller會替換掉那些刪除的或者被終止的pod,無論刪除的緣由是什麼(維護阿,更新啊,Replication Controller都不關心)。基於這個理由,咱們建議即便是隻建立一個pod,咱們也要使用Replication Controller。Replication Controller 就像一個進程管理器,監管着不一樣node上的多個pod,而不是單單監控一個node上的pod,Replication Controller 會委派本地容器來啓動一些節點上服務(Kubelet ,Docker)。nginx
Node是Pod真正運行的主機,能夠物理機,也能夠是虛擬機。爲了管理Pod,每一個Node節點上至少要運行container runtime(好比docker或者rkt)、kubelet和kube-proxy服務。web
每一個Node都包括如下狀態信息
ReplicaSet是下一代複本控制器。ReplicaSet和 Replication Controller之間的惟一區別是如今的選擇器支持。Replication Controller只支持基於等式的selector(env=dev或environment!=qa),但ReplicaSet還支持新的,基於集合的selector(version in (v1.0, v2.0)或env notin (dev, qa))。在試用時官方推薦ReplicaSet。
Kubernetes Pod是平凡的,它門會被建立,也會死掉(生老病死),而且他們是不可復活的。 ReplicationControllers動態的建立和銷燬Pods(好比規模擴大或者縮小,或者執行動態更新)。每一個pod都由本身的ip,這些IP也隨着時間的變化也不能持續依賴。這樣就引起了一個問題:若是一些Pods(讓咱們叫它做後臺,後端)提供了一些功能供其它的Pod使用(讓咱們叫做前臺),在kubernete集羣中是如何實現讓這些前臺可以持續的追蹤到這些後臺的?答案是:Service
Kubernete Service 是一個定義了一組Pod的策略的抽象,咱們也有時候叫作宏觀服務。這些被服務標記的Pod都是(通常)經過label Selector決定的(下面咱們會講到咱們爲何須要一個沒有label selector的服務)
容器中的磁盤的生命週期是短暫的,這就帶來了一系列的問題,第一,當一個容器損壞以後,kubelet 會重啓這個容器,可是文件會丟失-這個容器會是一個全新的狀態,第二,當不少容器在同一Pod中運行的時候,不少時候須要數據文件的共享。Kubernete Volume解決了這個問題.
一個Kubernetes volume,擁有明確的生命週期,與所在的Pod的生命週期相同。所以,Kubernetes volume獨立與任何容器,與Pod相關,因此數據在重啓的過程當中還會保留,固然,若是這個Pod被刪除了,那麼這些數據也會被刪除。更重要的是,Kubernetes volume 支持多種類型,任何容器均可以使用多個Kubernetes volume。
Deployment爲Pod和ReplicaSet提供了一個聲明式定義(declarative)方法,用來替代之前的ReplicationController來方便的管理應用。典型的應用場景包括:
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 3 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.7.9 ports: - containerPort: 80
Secret解決了密碼、token、密鑰等敏感數據的配置問題,而不須要把這些敏感數據暴露到鏡像或者Pod Spec中。Secret能夠以Volume或者環境變量的方式使用。
Secret有三種類型:
在本篇文章中你將會看到一些在其餘地方被交叉使用的術語,爲了防止產生歧義,咱們首先來澄清下。
什麼是Ingress?
一般狀況下,service和pod的IP僅可在集羣內部訪問。集羣外部的請求須要經過負載均衡轉發到service在Node上暴露的NodePort上,而後再由kube-proxy將其轉發給相關的Pod。
Ingress能夠給service提供集羣外部訪問的URL、負載均衡、SSL終止、HTTP路由等。爲了配置這些Ingress規則,集羣管理員須要部署一個Ingress controller,它監聽Ingress和service的變化,並根據規則配置負載均衡並提供訪問入口。
ConfigMap用於保存配置數據的鍵值對,能夠用來保存單個屬性,也能夠用來保存配置文件。ConfigMap跟secret很相似,但它能夠更方便地處理不包含敏感信息的字符串。
Kubernetes 經過各類 Controller 來管理 Pod 的生命週期。爲了知足不一樣業務場景,Kubernetes 開發了 Deployment、ReplicaSet、DaemonSet、StatefuleSet、Job 等多種 Controller。最經常使用的 Deployment用來創建Pod,如下是它的步驟
replicas的命名方式 :deployment名稱+隨機數
pod的命名方式:replicas名稱+隨機數
targetPort很好理解,targetPort是pod上的端口,從port和nodePort上到來的數據最終通過kube-proxy流入到後端pod的targetPort上進入容器。
這裏的port表示:service暴露在cluster ip上的端口,:port 是提供給集羣內部客戶訪問service的入口,而在集羣內部,各個服務之間咱們也能夠經過服務名+Port來訪問指定的服務,k8s內部會把服務解析到對應的pod上面。
nodePort是kubernetes提供給集羣外部客戶訪問service入口的一種方式(另外一種方式是LoadBalancer),因此,:nodePort 是提供給集羣外部客戶訪問service的入口。
# yaml格式的pod定義文件完整內容: apiVersion: v1 #必選,版本號,例如v1 kind: Pod #必選,Pod metadata: #必選,元數據 name: string #必選,Pod名稱 namespace: string #必選,Pod所屬的命名空間 labels: #自定義標籤 - name: string #自定義標籤名字 annotations: #自定義註釋列表 - name: string spec: #必選,Pod中容器的詳細定義 containers: #必選,Pod中容器列表 - name: string #必選,容器名稱 image: string #必選,容器的鏡像名稱 imagePullPolicy: [Always | Never | IfNotPresent] #獲取鏡像的策略 Alawys表示下載鏡像 IfnotPresent表示優先使用本地鏡像,不然下載鏡像,Nerver表示僅使用本地鏡像 command: [string] #容器的啓動命令列表,如不指定,使用打包時使用的啓動命令 args: [string] #容器的啓動命令參數列表 workingDir: string #容器的工做目錄 volumeMounts: #掛載到容器內部的存儲卷配置 - name: string #引用pod定義的共享存儲卷的名稱,需用volumes[]部分定義的的卷名 mountPath: string #存儲卷在容器內mount的絕對路徑,應少於512字符 readOnly: boolean #是否爲只讀模式 ports: #須要暴露的端口庫號列表 - name: string #端口號名稱 containerPort: int #容器須要監聽的端口號 hostPort: int #容器所在主機須要監聽的端口號,默認與Container相同 protocol: string #端口協議,支持TCP和UDP,默認TCP env: #容器運行前需設置的環境變量列表 - name: string #環境變量名稱 value: string #環境變量的值 resources: #資源限制和請求的設置 limits: #資源限制的設置 cpu: string #Cpu的限制,單位爲core數,將用於docker run --cpu-shares參數 memory: string #內存限制,單位能夠爲Mib/Gib,將用於docker run --memory參數 requests: #資源請求的設置 cpu: string #Cpu請求,容器啓動的初始可用數量 memory: string #內存清楚,容器啓動的初始可用數量 livenessProbe: #對Pod內個容器健康檢查的設置,當探測無響應幾回後將自動重啓該容器,檢查方法有exec、httpGet和tcpSocket,對一個容器只需設置其中一種方法便可 exec: #對Pod容器內檢查方式設置爲exec方式 command: [string] #exec方式須要制定的命令或腳本 httpGet: #對Pod內個容器健康檢查方法設置爲HttpGet,須要制定Path、port path: string port: number host: string scheme: string HttpHeaders: - name: string value: string tcpSocket: #對Pod內個容器健康檢查方式設置爲tcpSocket方式 port: number initialDelaySeconds: 0 #容器啓動完成後首次探測的時間,單位爲秒 timeoutSeconds: 0 #對容器健康檢查探測等待響應的超時時間,單位秒,默認1秒 periodSeconds: 0 #對容器監控檢查的按期探測時間設置,單位秒,默認10秒一次 successThreshold: 0 failureThreshold: 0 securityContext: privileged:false restartPolicy: [Always | Never | OnFailure]#Pod的重啓策略,Always表示一旦無論以何種方式終止運行,kubelet都將重啓,OnFailure表示只有Pod以非0退出碼退出才重啓,Nerver表示再也不重啓該Pod nodeSelector: obeject #設置NodeSelector表示將該Pod調度到包含這個label的node上,以key:value的格式指定 imagePullSecrets: #Pull鏡像時使用的secret名稱,以key:secretkey格式指定 - name: string hostNetwork:false #是否使用主機網絡模式,默認爲false,若是設置爲true,表示使用宿主機網絡 volumes: #在該pod上定義共享存儲卷列表 - name: string #共享存儲卷名稱 (volumes類型有不少種) emptyDir: {} #類型爲emtyDir的存儲卷,與Pod同生命週期的一個臨時目錄。爲空值 hostPath: string #類型爲hostPath的存儲卷,表示掛載Pod所在宿主機的目錄 path: string #Pod所在宿主機的目錄,將被用於同期中mount的目錄 secret: #類型爲secret的存儲卷,掛載集羣與定義的secre對象到容器內部 scretname: string items: - key: string path: string configMap: #類型爲configMap的存儲卷,掛載預約義的configMap對象到容器內部 name: string items: - key: string path: string
這些語法適合於rancher平臺,由於rancher平臺的底層也是k8s爲基礎的。
k8s用命名空間namespace
把資源進行隔離,默認狀況下,相同的命名空間裏的服務能夠相互通信,反之進行隔離。
Kubernetes中一個應用服務會有一個或多個實例(Pod,Pod能夠經過rs進行多複本的創建),每一個實例(Pod)的IP地址由網絡插件動態隨機分配(Pod重啓後IP地址會改變)。爲屏蔽這些後端實例的動態變化和對多實例的負載均衡,引入了Service這個資源對象,以下所示:
apiVersion: v1 kind: Service metadata: name: nginx-svc labels: app: nginx spec: type: ClusterIP ports: - port: 80 targetPort: 80 selector: #service經過selector和pod創建關聯 app: nginx
根據建立Service的type類型不一樣,可分紅4種模式:
ClusterIP
: 默認方式。根據是否生成ClusterIP又可分爲普通Service和Headless Service兩類:
固定虛擬IP
(Cluster IP),實現集羣內的訪問。爲最多見的方式。NodePort
:除了使用Cluster IP以外,還經過將service的port映射到集羣內每一個節點的相同一個端口,實現經過nodeIP:nodePort從集羣外訪問服
務。LoadBalancer
:和nodePort相似,不過除了使用一個Cluster IP和nodePort以外,還會向所使用的公有云申請一個負載均衡器(負載均衡器後端映射到各節點的nodePort),實現從集羣外經過LB訪問服務。ExternalName
:是 Service 的特例。此模式主要面向運行在集羣外部的服務,經過它能夠將外部服務映射進k8s集羣,且具有k8s內服務的一些特徵(如具有namespace等屬性),來爲集羣內部提供服務。此模式要求kube-dns的版本爲1.7或以上。這種模式和前三種模式(除headless service)最大的不一樣是重定向依賴的是dns層次,而不是經過kube-proxy。此時k8s集羣內的DNS服務會給集羣內的服務名 ..svc.cluster.local 建立一個CNAME記錄,其值爲指定的"my.database.example.com"。
當查詢k8s集羣內的服務my-service.prod.svc.cluster.local時,集羣的 DNS 服務將返回映射的CNAME記錄"foo.bar.example.com"。
備註:
前3種模式,定義服務的時候經過selector指定服務對應的pods,根據pods的地址建立出endpoints做爲服務後端;Endpoints Controller會watch Service以及pod的變化,維護對應的Endpoint信息。kube-proxy根據Service和Endpoint來維護本地的路由規則。當Endpoint發生變化,即Service以及關聯的pod發生變化,kube-proxy都會在每一個節點上更新iptables,實現一層負載均衡。
而ExternalName模式則不指定selector,相應的也就沒有port和endpoints。
ExternalName和ClusterIP中的Headles Service同屬於Headless Service的兩種狀況。Headless Service主要是指不分配Service IP,且不經過kube-proxy作反向代理和負載均衡的服務。
Service中主要涉及三種Port: * port
這裏的port表示service暴露在clusterIP上的端口,clusterIP:Port 是提供給集羣內部
訪問kubernetes服務的入口。
targetPort
containerPort,targetPort是pod上的端口,從port和nodePort上到來的數據最終通過kube-proxy流入到後端pod的targetPort上進入容器。
nodePort
nodeIP:nodePort 是提供給從集羣外部訪問kubernetes服務的入口。
總的來講,port和nodePort都是service的端口,前者暴露給從集羣內訪問服務,後者暴露給從集羣外訪問服務。從這兩個端口到來的數據都須要通過反向代理kube-proxy流入後端具體pod的targetPort,從而進入到pod上的容器內。
使用Service服務還會涉及到幾種IP:
ClusterIP
Pod IP 地址是實際存在於某個網卡(能夠是虛擬設備)上的,但clusterIP就不同了,沒有網絡設備承載這個地址。它是一個虛擬地址,由kube-proxy使用iptables規則從新定向到其本地端口,再均衡到後端Pod。當kube-proxy發現一個新的service後,它會在本地節點打開一個任意端口,建立相應的iptables規則,重定向服務的clusterIP和port到這個新建的端口,開始接受到達這個服務的鏈接。
Pod IP
Pod的IP,每一個Pod啓動時,會自動建立一個鏡像爲gcr.io/google_containers/pause的容器,Pod內部其餘容器的網絡模式使用container模式,並指定爲pause容器的ID,即:network_mode: "container:pause容器ID",使得Pod內全部容器共享pause容器的網絡,與外部的通訊經由此容器代理,pause容器的IP也能夠稱爲Pod IP。
節點IP
Node-IP,service對象在Cluster IP range池中分配到的IP只能在內部訪問,若是服務做爲一個應用程序內部的層次,仍是很合適的。若是這個service做爲前端服務,準備爲集羣外的客戶提供業務,咱們就須要給這個服務提供公共IP了。指定service的spec.type=NodePort,這個類型的service,系統會給它在集羣的各個代理節點上分配一個節點級別的端口,能訪問到代理節點的客戶端都能訪問這個端口,從而訪問到服務。
在k8s裏,你能夠經過服務名去訪問相同namespace裏的服務,而後服務能夠解析到對應的pod,從而再由pod轉到對應的容器裏,咱們能夠認爲這個過程有兩個port的概念,service port 就是服務的port,在k8s配置文件裏用port
表示,還有一個是pod和容器的port,用targetPort表示,其中pod和容器的port你能夠認爲它是一個。
咱們一般會把mysql,redis,rabbitmq,mongodb這些公用組件放在一個namespace裏,或者每一個公用組件都有本身的namespace,而你的業務組件會統一放在本身的namespace裏,這時就涉及到了跨namespace的數據通信問題。
Kubernetes 目前使用的kube-dns來實現集羣內部的service dns記錄解析。默認狀況下/etc/resolv.conf裏,它的內容是統一的格式。
/ # more /etc/resolv.conf
nameserver 172.19.0.10 search saas.svc.cluster.local svc.cluster.local cluster.local options ndots:5
search doamin列表默認狀況下,它只包含本地域名
。這能夠經過在search關鍵字後面列出所需的域搜索路徑來添加。kubernetes爲每一個容器配置默認是${namespace}.svc.cluster.local
svc.cluster.local
cluster.local
。在一次dns域名查詢時,將會嘗試使用每一個search doamin依次搜索少於ndots點(默認值爲1)的解析器查詢,直到找到匹配項。對於具備多個子域的環境,建議調整選項ndots:n,以免man-in-the-middle攻擊和root-dns-servers的沒必要要通訊。
這個咱們能夠把它理解成服務名dns解析的層次,例如{服務名}是一級,而{服務名}.{命名空間}爲二層,{服務名}.{命名空間}.svc.cluster.local是第三層,上面的配置一共有5層,同時也開啓了5層,這樣作能夠保證最大限度的找到你的服務,但對於解析的性能是有影響的。
請注意,若是搜索域對應的服務器不是本地的,那麼這個查詢過程可能會很慢,而且會產生大量的網絡流量。若是其中一個搜索域域沒有可用的服務器,則查詢將超時。
若是你要鏈接namespace是redis的,服務名是redis-master的服務,你能夠這樣去配置你的鏈接:
spring: profiles: redis-prod redis: host: redis-master.redis port: 6379 password: 123456 database: 1
它採用了服務名+命名空間的格式,若是是相同的namespace,能夠直接使用服務名來解析。
ClusterIP的方式只能在集羣內部訪問
NodePort方式的話,測試環境使用還行,當有幾十上百的服務在集羣中運行時,NodePort的端口管理是災難。
LoadBalance方式受限於雲平臺,且一般在雲平臺部署ELB還須要額外的費用。
所幸k8s還提供了一種集羣維度暴露服務的方式,也就是ingress。ingress能夠簡單理解爲service的service,他經過獨立的ingress對象來制定請求轉發的規則,把請求路由到一個或多個service中。這樣就把服務與請求規則解耦了,能夠從業務維度統一考慮業務的暴露,而不用爲每一個service單獨考慮,下面是一個簡單的ingress應用圖,實現了簡單的請求轉發
ingress對象:
指的是k8s中的一個api對象,通常用yaml配置。做用是定義請求如何轉發到service的規則,能夠理解爲配置模板。
ingress-controller:
具體實現反向代理及負載均衡的程序,對ingress定義的規則進行解析,根據配置的規則來實現請求轉發。
簡單來講,ingress-controller纔是負責具體轉發的組件,經過各類方式將它暴露在集羣入口,外部對集羣的請求流量會先到ingress-controller,而ingress對象是用來告訴ingress-controller該如何轉發請求,好比哪些域名哪些path要轉發到哪些服務等等。
ingress-controller並非k8s自帶的組件,實際上ingress-controller只是一個統稱,用戶能夠選擇不一樣的ingress-controller實現,目前,由k8s維護的ingress-controller只有google雲的GCE與ingress-nginx兩個,其餘還有不少第三方維護的ingress-controller,具體能夠參考 官方文檔。可是無論哪種ingress-controller,實現的機制都大同小異,只是在具體配置上有差別。通常來講,ingress-controller的形式都是一個pod,裏面跑着daemon程序和反向代理程序。daemon負責不斷監控集羣的變化,根據ingress對象生成配置並應用新配置到反向代理,好比nginx-ingress就是動態生成nginx配置,動態更新upstream,並在須要的時候reload程序應用新配置。爲了方便,後面的例子都以k8s官方維護的nginx-ingress爲例。
2 咱們的ingress是支持https的,因此須要爲你的域名配置對應的證書,咱們在配置文件裏添加
3 自動爲ingress-controller裏的配置文件添加nginx配置項,而後自動reload它,讓它生效
當有新的ingress服務註冊以後,配置文件會發生變化
4 你的服務對應的nginx是在本身服務的ymal裏進行配置的,通常來講,微服務的網關層都應該創建 一個ingress-nginx來對外提供服務!
# 構建反射代理 kind: Ingress apiVersion: extensions/v1beta1 metadata: name: hello-world-ingress namespace: saas annotations: kubernetes.io/ingress.class: "nginx" nginx.ingress.kubernetes.io/use-regex: "true" spec: tls: - hosts: - www.abc.com secretName: saas-tls rules: - host: www.abc.com http: paths: - backend: serviceName: hello-world servicePort: 9001
## start server www.abc.com server { server_name www.abc.com ; listen 80 ; listen [::]:80 ; listen 443 ssl http2 ; listen [::]:443 ssl http2 ; set $proxy_upstream_name "-"; # PEM sha: c24ba9e405ed77662c0fd7546a908ef45ca76066 ssl_certificate /etc/ingress-controller/ssl/default-fake-certificate.pem; ssl_certificate_key /etc/ingress-controller/ssl/default-fake-certificate.pem; ssl_certificate_by_lua_block { certificate.call() } location ~* "^/" { set $namespace "saas"; set $ingress_name "hello-world-ingress"; set $service_name "hello-world"; set $service_port "{0 9001 }"; set $location_path "/"; rewrite_by_lua_block { lua_ingress.rewrite({ force_ssl_redirect = true, use_port_in_redirects = false, }) balancer.rewrite() plugins.run() } header_filter_by_lua_block { plugins.run() } body_filter_by_lua_block { } log_by_lua_block { balancer.log() monitor.call() plugins.run() } if ($scheme = https) { more_set_headers "Strict-Transport-Security: max-age=15724800; includeSubDomains"; } port_in_redirect off; set $balancer_ewma_score -1; set $proxy_upstream_name "saas-hello-world-9001"; set $proxy_host $proxy_upstream_name; set $pass_access_scheme $scheme; set $pass_server_port $server_port; set $best_http_host $http_host; set $pass_port $pass_server_port; set $proxy_alternative_upstream_name ""; client_max_body_size 1m; proxy_set_header Host $best_http_host; # Pass the extracted client certificate to the backend # Allow websocket connections proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_set_header X-Request-ID $req_id; proxy_set_header X-Real-IP $the_real_ip; proxy_set_header X-Forwarded-For $the_real_ip; proxy_set_header X-Forwarded-Host $best_http_host; proxy_set_header X-Forwarded-Port $pass_port; proxy_set_header X-Forwarded-Proto $pass_access_scheme; proxy_set_header X-Original-URI $request_uri; proxy_set_header X-Scheme $pass_access_scheme; # Pass the original X-Forwarded-For proxy_set_header X-Original-Forwarded-For $http_x_forwarded_for; # mitigate HTTPoxy Vulnerability # https://www.nginx.com/blog/mitigating-the-httpoxy-vulnerability-with-nginx/ proxy_set_header Proxy ""; # Custom headers to proxied server proxy_connect_timeout 5s; proxy_send_timeout 60s; proxy_read_timeout 60s; proxy_buffering off; proxy_buffer_size 4k; proxy_buffers 4 4k; proxy_request_buffering on; proxy_http_version 1.1; proxy_cookie_domain off; proxy_cookie_path off; # In case of errors try the next upstream server before returning an error proxy_next_upstream error timeout; proxy_next_upstream_timeout 0; proxy_next_upstream_tries 3; proxy_pass http://upstream_balancer; proxy_redirect off; } } ## end server www.abc.com
查看全部 pod 列表, -n 後跟 namespace, 查看指定的命名空間
kubectl get pod kubectl get pod -n kube kubectl get pod -o wide
查看 RC 和 service 列表, -o wide 查看詳細信息
kubectl get rc,svc kubectl get pod,svc -o wide kubectl get pod <pod-name> -o yaml
顯示 Node 的詳細信息
kubectl describe node 192.168.0.212
顯示 Pod 的詳細信息, 特別是查看 pod 沒法建立的時候的日誌
kubectl describe pod <pod-name> eg: kubectl describe pod redis-master-tqds9
根據 yaml 建立資源, apply 能夠重複執行,create 不行
kubectl create -f pod.yaml kubectl apply -f pod.yaml
基於 pod.yaml 定義的名稱刪除 pod
kubectl delete -f pod.yaml
刪除全部包含某個 label 的pod 和 service
kubectl delete pod,svc -l name=<label-name>
刪除全部 Pod
kubectl delete pod --all
查看 endpoint 列表
kubectl get endpoints
執行 pod 的 date 命令
kubectl exec <pod-name> -- date kubectl exec <pod-name> -- bash kubectl exec <pod-name> -- ping 10.24.51.9
經過bash得到 pod 中某個容器的TTY,至關於登陸容器
kubectl exec -it <pod-name> -c <container-name> -- bash eg: kubectl exec -it redis-master-cln81 -- bash
查看容器的日誌
kubectl logs <pod-name> kubectl logs -f <pod-name> # 實時查看日誌 kubectl log <pod-name> -c <container_name> # 若 pod 只有一個容器,能夠不加 -c
查看註釋
kubectl explain pod kubectl explain pod.apiVersion
作爲 Kubernetes 的一個包管理工具,Helm具備以下功能:
本文中講到的是helm V2最新版本,V3版本也已經發布了beta版,在 Helm 3 中,Tiller 被移除了。
Helm
Helm 是一個命令行下的客戶端工具。主要用於 Kubernetes 應用程序 Chart 的建立、打包、發佈以及建立和管理本地和遠程的 Chart 倉庫。
Tiller
Tiller 是 Helm 的服務端,部署在 Kubernetes 集羣中。Tiller 用於接收 Helm 的請求,並根據 Chart 生成 Kubernetes 的部署文件( Helm 稱爲 Release ),而後提交給 Kubernetes 建立應用。Tiller 還提供了 Release 的升級、刪除、回滾等一系列功能。
Chart
包含了建立Kubernetes的一個應用實例的必要信息,Helm 的軟件包,採用 TAR 格式。相似於 APT 的 DEB 包或者 YUM 的 RPM 包,其包含了一組定義 Kubernetes 資源相關的 YAML 文件。
Repoistory
Helm 的軟件倉庫,Repository 本質上是一個 Web 服務器,該服務器保存了一系列的 Chart 軟件包以供用戶下載,而且提供了一個該 Repository 的 Chart 包的清單文件以供查詢。Helm 能夠同時管理多個不一樣的 Repository。
Release
是一個 chart 及其配置的一個運行實例,使用 helm install 命令在 Kubernetes 集羣中部署的 Chart 稱爲 Release。
Chart Install 過程
Helm 從指定的目錄或者 TAR 文件中解析出 Chart 結構信息。
Helm 將指定的 Chart 結構和 Values 信息經過 gRPC 傳遞給 Tiller。
Tiller 根據 Chart 和 Values 生成一個 Release。
Tiller 將 Release 發送給 Kubernetes 用於生成 Release。
Chart Update 過程
Helm 從指定的目錄或者 TAR 文件中解析出 Chart 結構信息。
Helm 將須要更新的 Release 的名稱、Chart 結構和 Values 信息傳遞給 Tiller。
Tiller 生成 Release 並更新指定名稱的 Release 的 History。
Tiller 將 Release 發送給 Kubernetes 用於更新 Release。
Chart Rollback 過程
Helm 將要回滾的 Release 的名稱傳遞給 Tiller。
Tiller 根據 Release 的名稱查找 History。
Tiller 從 History 中獲取上一個 Release。
Tiller 將上一個 Release 發送給 Kubernetes 用於替換當前 Release。
Chart 處理依賴說明
Tiller 在處理 Chart 時,直接將 Chart 以及其依賴的全部 Charts 合併爲一個 Release,同時傳遞給 Kubernetes。所以 Tiller 並不負責管理依賴之間的啓動順序。Chart 中的應用須要可以自行處理依賴關係。
上一講說了一些helm的基本概念,而今天主要說一下如何把helm部署到服務器上,在helm3以前的版本里,它由客戶端helm和服務端tiller組成,而helm3.0以後它去掉了tiller,而直接與k8s通信,能夠說在部署上更簡單了,而今天咱們主要仍是部署2.x版本的helm.
https://get.helm.sh/helm-v2.16.5-linux-amd64.tar.gz
apiVersion: v1 kind: ServiceAccount metadata: name: tiller namespace: kube-system --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRoleBinding metadata: name: tiller roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - kind: ServiceAccount name: tiller namespace: kube-system
kubectl create -f rbac-config.yaml
helm init --service-account tiller --skip-refresh
對於 Kubernetes v1.16.0 以上的版本,有可能會碰到 Error: error installing: the server could not find the requested resource 的錯誤。這是因爲 extensions/v1beta1 已經被 apps/v1 替代。相信在2.15 或者 3 版本發佈以後, 應該就不會遇到這個問題了。仍是生態比較慢的緣由。
helm init -i registry.cn-hangzhou.aliyuncs.com/google_containers/tiller:v2.14.3 --stable-repo-url http://mirror.azure.cn/kubernetes/charts/ --service-account tiller --override spec.selector.matchLabels.'name'='tiller',spec.selector.matchLabels.'app'='helm' --output yaml | sed 's@apiVersion: extensions/v1beta1@apiVersion: apps/v1@' | kubectl apply -f -
kubectl get pods -n kube-system | grep tiller tiller-deploy-7c7b67c9fd-kxh6p 1/1 Running 0 4m58s
到如今爲止,咱們的helm就安裝功能了,以後咱們裝運行helm來進行charts的安裝
上級講了helm2的安裝,而且在安裝過程當中可能會出現問題,主要是與k8s版本衝突的問題,而最新的helm3對整個helm的架構都有了一個改進,它只有一個客戶端的helm程序,由它進行鏈接k8s集羣,完成對charts的部署工做。
https://get.helm.sh/helm-v3.0.0-linux-amd64.tar.gz
[root@i-pcwovafu bin]# helm env HELM_NAMESPACE="default" HELM_KUBECONTEXT="" HELM_BIN="helm" HELM_DEBUG="false" HELM_PLUGINS="/root/.local/share/helm/plugins" HELM_REGISTRY_CONFIG="/root/.config/helm/registry.json" HELM_REPOSITORY_CACHE="/root/.cache/helm/repository" HELM_REPOSITORY_CONFIG="/root/.config/helm/repositories.yaml"
helm repo add stable http://mirror.azure.cn/kubernetes/charts helm repo add aliyun https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts helm repo update
這一步很是關鍵,它是helm與k8s通信的保證,這一步就是把k8s環境變量KUBECONFIG進行配置
export KUBECONFIG=/root/.kube/config #能夠寫到/etc/profile裏
[root@i-pcwovafu ~]# helm search hub nginx URL CHART VERSION APP VERSION DESCRIPTION https://hub.helm.sh/charts/choerodon/nginx-file... 0.1.0 1.13.5-alpine A Helm chart for Kubernetes https://hub.helm.sh/charts/cloudposse/nginx-ing... 0.1.8 A Helm chart for Nginx Ingress https://hub.helm.sh/charts/cloudposse/nginx-def... 0.5.0 A Helm chart for nginx-default-backend to be us... https://hub.helm.sh/charts/cloudposse/fail-whale 0.1.1 A Helm chart that provides a mainte
helm create nginx helm nignx-demo ./nginx
[root@i-pcwovafu bin]# rancher kubectl get pods -n default NAME READY STATUS RESTARTS AGE web-nginx-858f7d9cc5-hlhkj 1/1 Running 0 2m14s
也可使用helm命令來查看
[root@i-pcwovafu bin]# helm list NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION web-nginx default 1 2020-04-07 17:09:53.480335758 +0800 CST deployed nginx-0.1.0 1.16.0
這樣一個最簡單的helm應用就創建好了!
helm create hello-world
Chart.yaml 用於描述這個Chart的相關信息,包括名字、描述信息以及版本等。
僅僅是一些簡單的文本描述
values.yaml 用於存儲 templates 目錄中模板文件中用到變量的值。
NOTES.txt 用於介紹 Chart 部署後的一些信息,例如:如何使用這個 Chart、列出缺省的設置等。
Templates 目錄下是 YAML 文件的模板,該模板文件遵循 Go template 語法。
Templates 目錄下 YAML 文件模板的值默認都是在 values.yaml 裏定義的,好比在 deployment.yaml 中定義的容器鏡像。
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
其中的 .Values.image.repository 的值就是在 values.yaml 裏定義的 nginx,.Values.image.tag 的值就是 stable。
以上兩個變量值是在 create chart 的時候就自動生成的默認值,你能夠根據實際狀況進行修改。實際上都是靜態文本,只在是執行的時候才被解析.
打開 Chart.yaml,能夠看到內容以下,配置名稱和版本
apiVersion: v1 appVersion: "1.0" description: A Helm chart for Kubernetes name: mychart version: 0.1.0
編輯 values.yaml,它默認會在 Kubernetes 部署一個 Nginx。下面是 mychart 應用的 values.yaml 文件的內容:
$ cat mychart/values.yaml # Default values for mychart. # This is a YAML-formatted file. # Declare variables to be passed into your templates. replicaCount: 1 image: repository: nginx tag: stable pullPolicy: IfNotPresent service: type: ClusterIP port: 80 ingress: enabled: false annotations: {} # kubernetes.io/ingress.class: nginx # kubernetes.io/tls-acme: "true" path: / hosts: - chart-example.local tls: [] # - secretName: chart-example-tls # hosts: # - chart-example.local resources: {} # We usually recommend not to specify default resources and to leave this as a conscious # choice for the user. This also increases chances charts run on environments with little # resources, such as Minikube. If you do want to specify resources, uncomment the following # lines, adjust them as necessary, and remove the curly braces after 'resources:'. # limits: # cpu: 100m # memory: 128Mi # requests: # cpu: 100m # memory: 128Mi nodeSelector: {} tolerations: [] affinity: {}
$ helm lint hello-world/
helm package hello-world helm package mychart --debug #顯示詳細信息
helm serve --repo-path /data/helm/repository/ --url http://172.17.0.22:8879/charts/ &
$ helm repo update $ helm search mychart NAME CHART VERSION APP VERSION DESCRIPTION local/hello-world 0.1.0 1.0 A Helm chart for Kubernetes
Chart 被髮布到倉儲後,就能夠經過 helm install 命令部署該 Chart。
helm install hello local/hello-world
helm status wordpress
helm upgrade wordpress stable/wordpress
helm upgrade --install --force hello-world ./hello.tgz --namespace test # 也能夠指定命名空間和它的taz包
helm rollback hello-world 1 # 向上歸滾一個版本
能夠在requirements.yaml裏去配置它的依賴關係, 它支持兩種方式表示依賴關係,可使用requirements.yaml或者直接將依賴的Chart放置到charts目錄中。
dependencies: - name: mariadb version: 7.x.x repository: https://kubernetes-charts.storage.googleapis.com/ condition: mariadb.enabled tags: - wordpress-database
templates目錄下的yaml文件,遵循Go template語法。使用過Hugo的靜態網站生成工具的人應該對此很熟悉。
templates目錄中存放了Kubernetes部署文件的模版,好比deployment.yaml,service.yaml等,它裏面引用的變量來自values.yaml裏
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
上面的{{ .Values.image.repository }}
表示values.yaml文件裏的image節點下的repository元素的內容
k8s應用(包括有狀態跟無狀態應用),須要使用數據卷的話,須要在存儲卷中進行設置和聲明,下面列出持久化數據卷的聲明跟設置的模板:
數據卷設置:
apiVersion: v1 kind: PersistentVolume -這裏說明是持久化數據卷 metadata: finalizers: - kubernetes.io/pv-protection labels: alicloud-pvname: {{ .Values.volumes.name }} -數據卷標籤,eg:XXX-data name: {{ .Values.volumes.name }} -數據卷名稱,eg:XXX-data spec: accessModes: - ReadWriteMany -權限 capacity: storage: {{ .Values.volumes.storage }} -容量大小,eg:10Gi flexVolume: driver: alicloud/nas -數據卷類型是nas options: path: {{ .Values.volumes.path }} -數據卷路徑,eg:/tmp server: {{ .Values.volumes.server }} -數據卷服務商,eg:xxxxx.nas.aliyuncs.com vers: '3' persistentVolumeReclaimPolicy: Retain storageClassName: nas
數據卷聲明:
apiVersion: v1 kind: PersistentVolumeClaim -持久化數據卷聲明 metadata: annotations: pv.kubernetes.io/bind-completed: 'yes' pv.kubernetes.io/bound-by-controller: 'yes' finalizers: - kubernetes.io/pvc-protection name: {{ .Values.volumes.name }} spec: accessModes: - ReadWriteMany resources: requests: storage: {{ .Values.volumes.storage }} -容量,eg:10Gi selector: matchLabels: alicloud-pvname: {{ .Values.volumes.name }} storageClassName: nas volumeName: {{ .Values.volumes.name }}
應用彈性伸縮配置,這個能夠配置最大、最小副本集跟伸縮條件的參數到values.yaml文件裏面
kind: HorizontalPodAutoscaler apiVersion: autoscaling/v1 metadata: name: {{ include "admin.appname" . }}-hpa -admin.appname就是後面執行helm命令的時候倒數第二個參數,爲何前面是admin呢,admin就是你配置Chart.yaml的時候裏面的name變量的值 spec: scaleTargetRef: kind: Deployment name: {{ include "admin.appname" . }} apiVersion: apps/v1beta2 minReplicas: 1 -最小副本集 maxReplicas: 10 -最大副本集 targetCPUUtilizationPercentage: 70 -伸縮條件
配置項設置,通常每一個項目有都對應的環境參數,好比:數據庫、redis等這些帳號密碼類的參數,這些能夠抽離出來當成一個配置項處理
apiVersion: v1 kind: ConfigMap metadata: name: {{ .Values.envConfigName }} -每一個環境就配置一個配置項 data: {{- range $k, $v := .Values.configDatas }} -這裏是循環遍歷configDatas這個變量 {{ $k | indent 2 }}.yml: >- -下面這兩行配置一個key->value的配置項(即文件名->文件內容) {{ $v | indent 4 }} {{- end -}}
將鏡像的密碼配置到保密字典中
apiVersion: v1 kind: Secret metadata: name: image-secret -name隨意寫 data: .dockerconfigjson: {{ .Files.Get "image.pwd" | b64enc }} -內容 type: kubernetes.io/dockerconfigjson
TLs證書配置(後面配置ingress的時候要用到,否則沒法用https)
apiVersion: v1 kind: Secret metadata: name: tls-secret data: tls.crt: {{ .Files.Get "XXXXX.com.pem" | b64enc }} tls.key: {{ .Files.Get "XXXXX.com.key" | b64enc }} type: Opaque
下次主要說一下幾個重要的yaml文件的模板。