【編者的話】這是介紹Kubernetes的第三篇,主要集中講述如何配置Kubernetes集羣以及做者在配置過程當中遇到的問題。html
在本系列文章的第一部分中,咱們探討了容器、Docker以及這些技術如何從新定義行業中的基礎設施及其運營方式。第二部分文章則繼續討論,着眼點放在Kubernetes身上——包括Kubernetes是什麼以及擁有哪些能力。在今天的第三部分文章中,我將進一步闡述如何上手Kubernetes,同時提供與結構設計相關的一點參考意見。github
Kubernetes的集羣管理是經過kubectl
命令進行的,若是你使用Google Cloud,則會在SDK中自動安裝kubectl
命令行工具。雖然你能夠徹底使用這個命令行工具來配置、控制Kubernetes集羣,可是我仍是十分推薦你使用單獨的配置文件來配置集羣,由於你可使用版本控制工具來追蹤每次對集羣配置的修改並且保證配置的統一,後面會着重介紹如何去作。web
kubectl
命令集合包含了很是多的子命令來幫助你控制Kubernetes集羣的方方面面,如窺探當前集羣的工做狀態等等。下面是我以爲很是經常使用的幾個命令,並將其分類說明。redis
kubectl apply -f service-file.yml
apply
命令會收集配置文件(service-file.yml)中全部的配置項信息,並自動將配置文件中的配置項跟當前集羣的運行配置作對比,而後自動將必要的更新應用到當前集羣中。kubectl rollout
全部經過apply
命令觸發的指令都會生成一個新的Rollout對象。經過使用kubectl rollout status
命令能夠查看最近的更新狀態、終止一個rollout或者回滾到上一個資源對象(Deployment,Pod,Service等)的版本。docker
kubectl describe [pod,service,...] [resource]
這條命令能夠查看某個資源的詳細信息,當錯誤發生的時候你必須首選考慮使用describe
命令來獲取錯誤描述信息。kubectl logs [resource]
Kubernetes內的容器會傾向於把全部的日誌定向到STDOUT
上,kubectl logs -f
命令能讓你獲取一個資源(Pod/Container)最新的日誌。kubectl get [pods,deployments,services,...]
這條命令會將Kubernetes默認命名空間中運行的資源信息打印出來,若是要看特定命名空間的資源信息,則必須加上--namespace=[my namespace]
參數,若是查看全部命名空間的資源信息,則使用--all-namespace
參數。kubectl exec
這條命令是對docker exec
命令的包裝,可讓你執行容器內部的命令,若是pod中只有一個容器在運行則此命令能夠做用在pod上如:kubectl exec -it [pod] /bin/bash
。咱們可使用kubectl exec -it [pod name] --/bin/bash
來進入一個運行中的pod,-i
用來啓動標準輸入流STDIN
,-t
將輸入流定向到TTY(僞終端)中,這樣就能模擬終端的bash命令操做了。固然若是一個Pod中啓動了多個容器,你可使用-C[container-name]
參數來進入特定的容器中。數據庫
當前尚未命令可以讓一個Deployment自動將配置的Pod下的容器更新到最新的版本;可是爲Kubernetes集羣更新容器版本又是一個很是常見的操做,這時你就必須想清楚更新容器的步驟了,我列出如下幾種方法:json
:latest
的Tag,而後手動刪除運行中的Pod,而後Deployment會自動用最新的容器從新啓動Pod; apply
這個配置文件到Kubernetes的集羣中,這種方式須要對配置文件進行版本控制;kubectl set image deployment/[service name] *=[new image]
。我須要的方案是即可以在Kubernetes中留下更改歷史,也不想由於總是去提交配置文件的更改致使陷入版本混亂的泥沼。因此,我我的選擇第三種方案,我是這麼操做的:api
:latest
tag;:latest
tag之外還要打上與代碼git倉庫HEAD指針指向的Commit號相同的tag(如:9c713a);kubectl set image deployment/[service name] *=[new image]
時填入git commit hash號標識的鏡像。根據以上幾點,我能夠得到一些好處:緩存
set image
命令來更新Pods的鏡像很是的優雅,由於可使用kubectl rollout status
來跟蹤全部Deployment的Pods的更新狀態;:latest
tag的鏡像(注:在測試環境或者非生產環境使用git commit hash號來啓動容器,可是在生產時使用:latest
,由於做者在push鏡像時同時打了兩個tag)。Kubernetes開發人員不只提供了至關全面的文檔能夠參考,並且提供了minikube這個可讓開發者在本地環境運行Kubernetes集羣的工具。minikube能夠運行在多種不一樣的虛擬化環境下,它能夠很容易的啓動一個全功能的,包含一個單一節點的Kubernetes集羣。當集羣啓動後,minikube提供了多種命令來訪問與窺探集羣運行狀況,同時kubectl工具也是自動爲minikube配置好的。最經常使用的命令莫過於:minikube service [service name] --url
這條命令可以打印出本地集羣中配好的Service的訪問url地址。minikube dashboard
這會跳轉到一個web-based的集羣看板頁面,幫助你經過可視化的方式瞭解集羣運行的情況。
同時我建議將運行minikube的默認的VM配置加高一點,好比配置:4CPUs與8GB內存,使用VMWare Fusion 做爲VM容器,例如可使用以下命令:minikube config set cpus 4 minikube config set memory 8192 minikube start --vm-driver vmwarefusion
若是要讓kubectl退出對minikube的訪問,必須從新配置kubectl讓它鏈接到新的集羣;以下命令:kubectl config get-contexts kubectl config use-context [cluster context name from above]
固然,若是要從新鏈接到本地的minikube,只須要使用這條命令:kubectl config use-context minikube
Service的配置文件支持JSON與YAML,可是我推薦使用YAML,由於它比較容易讀寫,並且支持註釋,這對那些複雜的結構很是管用。
對於集羣的配置,Service每每是最早配置的,這就是所謂的Service-first配置法。具體的作法是,爲每一個要建立的服務分配一個單獨的文件夾,這個文件夾中包含了全部啓動這個服務的配置文件。爲了搜索方面,我建議爲每一個Kubernetes的Service資源建立一個yaml配置文件,能夠這樣命名:[service name]-k8s.yml
,這個配置文件中寫入全部這個Service在Kubernetes環境啓動的配置項。
以下是我配置一個Redis緩存服務的目錄結構:
redis-cache/
Dockerfile
redis.conf
redis-cache-k8s.yml複製代碼
如下是服務配置文件redis-cache-k8s.yml:
```apiVersion: v1
kind: Service
metadata:
name: redis-cache
labels:
role: cache
spec:
type: NodePort
ports:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: redis-cache
spec:
revisionHistoryLimit: 3
replicas: 1
template:
metadata:
labels:
role: cache
spec:
containers:
- name: redis
image: redis:3
resources:
requests:
cpu: 100m
memory: 1Gi
ports:
- containerPort: 6379 ```複製代碼
而後經過運行apply -f service/redis-cache/redis-cache-k8s.yml
命令就能讓redis-cache服務在整個Deployment中跑起來。
我如今爲每一個容器都打兩個tag分別是::latest
與對應代碼git庫中的HEAD指針Commit的hash值如::9c713a
。不少人強烈推薦不要使用:latest
tag,緣由在這裏(注:內容大概講docker registry並不會主動判斷一個鏡像是不是最新的,而是能夠人爲的隨意爲一個老的鏡像打上latest tag的,因此不少人認爲latest標籤的鏡像其實並不必定是最新的),可是我以爲這些都是講給那些只用latest標籤的人聽的。我爲何這麼作的緣由在上面「部署新鏡像」一節已經闡述。
我早期使用minikube遇到的問題是如何讓個人Pod有權限從個人Google私有鏡像倉庫中拉取docker鏡像。固然,當我在GKE中使用Kubernetes集羣拉取鏡像是沒有問題的,由於當使用GKE時,全部的服務器都自動被賦予了訪問Google私有鏡像倉庫的的權限,可是做爲本地運行的minikube就沒有權限了。
解決方法是在Pod的spec節中使用imagePullSecrets
值。首先,登陸Google Cloud,而後前往IAM並建立一個新的Service Account
並賦予Storage -> Storage Object Viewer
權限,確保勾選「Furnish a new private key」選項,完過後會給你一個JSON文件,這個文件你須要本地保存,是用於受權的;全部這些準備就緒後運行這段腳本生成一個新的Secret資源:
`#!/usr/bin/env sh
SPATH="$(cd $(dirname "$0") && pwd -P)"
SECRET_NAME=${1:-docker-registry-secret}
CONFIG_PATH=${2:-$SPATH/localkube.json}
if [[ ! -f $CONFIG_PATH ]]; then
echo "Unable to locate service account config JSON: $CONFIG_PATH";
exit 1;
fi
kubectl create secret docker-registry $SECRET_NAME \
--docker-server "gcr.io" \
--docker-username _json_key \
--docker-email [service account email address] \
--docker-password="cat $CONFIG_PATH
" ${@:3} 這段腳本會生成一個名爲
docker-registry-secret的Secret資源,這個資源稍後要在Service的配置文件中的
imagePullSecrets值中被引用,以下所示:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: redis-cache
spec:
...
template:
spec:
imagePullSecrets:
- name: docker-registry-secret
...
containers:
- name: redis
image: gcr.io/[google account id]/redis-cache:latest複製代碼
...`
配置完成後應該就能從Google私有鏡像倉庫中拉取鏡像了。
敏感的數據好比:密碼,認證碼與各類key,這些都是要作特殊處理並很容易出錯的數據。首先,若是將這些數據不加密的保存在代碼管理倉庫中,無論這個倉庫多麼機密,並非一個保險的作法;但同時,你又必須把這些數據加密並保存在某個安全的地方,並使用一個跟蹤系統對其作版本記錄與權限控制。我使用了不少不一樣的加密、保存方式,發現StackExchange的BlackBox很是好用。
BlackBox使用PGP/GPG(非對稱加密)加密方式對文件進行加密,確保只有特定的用戶才能訪問加密的文件。對一個用戶受權訪問某個資源只需這個用戶提供本身的GPG公鑰,而移除一個用戶的受權只須要在一些配置文件中將其名字去掉便可;而後你要作的事就是告訴BlackBox哪些文件須要加密,而其他的工做交給BlackBox便可,被加密的配置文件能夠放心的放入git倉庫了。
將這些加密的信息提供給Kubernetes須要一些額外的本地腳本,由於Kubernetes將配置信息以明文的方式存儲在etcd中。好比:我會對兩類文件進行加密:一、YAML配置文件,內部包含不少key-value形式保存的敏感信息(如:數據庫密碼等);二、一些公鑰文件如:SSL Certificate或者其餘祕鑰。而後,我使用rake來解密這些文件,而後將解密的文件應用到Kubernetes集羣中,使用命令:apply -f -
(注意:'-'表示STDIN)。
好比,我有個加密的YAML文件,以下:--- rails: secret_key_base: "..." service_api_key: "..." database: username: "..." password: "..."
而後導入Kubernetes的Secret:raw_secrets =
blackbox_cat secrets/my-secrets.yml.gpg`
secrets = YAML.load(raw_secrets)
secrets.each do |name, values|
k8s_secret = {
"apiVersion" => "v1",
"kind" => "Secret",
"type" => "Opaque",
"metadata" => { "name" => name },
"data" => {},
}
values.each do |key, value|
k8s_secret["data"][key] = Base64.strict_encode64(value)
end
stdout, status = Open3.capture2("kubectl apply -f -", stdin_data: k8s_secret.to_yaml)
end 而後在Service的配置文件中來引用這些Secret(使用Secret名稱,我一般使用環境變量來指定):
...
env:
name: rails
key: secret_key_base複製代碼
name: rails
key: service_api_key複製代碼
name: database
key: username複製代碼
name: database
key: password`複製代碼
我認爲這是我使用、配置Kubernetes過程當中遇到的主要問題,但願對您有幫助。原文連接:CONTAINERS, DOCKER, AND KUBERNETES PART 3(翻譯:肖勁)