前言
相信很多公司都有集成發布pass系統,底層大多數依賴於k8s來進行服務的發布部署/回滾等功能。
對於很多業務開發者都是不可見的,在感嘆這個東西真好用的同時,想着探一探這背后的原理。
真正的入門還是得自己親手跑起來!
今天這篇k8s入門我整理了必會的幾個k8s知識點
- docker的使用,鏡像的創建和發布(我當你已經會了哈)
- k8s開發環境搭建
- Deployment的使用
- Service的使用
- ConfigMap的使用
學習環境搭建
首先k8s學習的話是建議用minikube搭建,這里系統我用的ubuntu20.04.2.0LTS
我這里用的是vmware虛擬機,
如果FQ不順利的話請加我微信獲取已經裝好環境的虛擬機(節省你時間不香嗎),前提你的機器得是32G內存或以上
假設你自己裝了,或者你用了我的vmware虛擬機,或者你用docker Desktop裝的k8s,那么啟動后
敲命令來啟動minikube:
minikube start
耐心等待完成后使用 minikube status 查看狀態是否是Running:
然后我們要啟動k8s控制面板-dashbord服務,下面的命令里 —url 的意思是啟動后,打印dashbord的url。不帶的話會啟動你本機瀏覽器打開。
minikube dashboard --url
k8s的控制面板默認的是本機(localhost)才能打開,所以需要使用k8s的proxy功能,到虛擬機的terminal窗口敲入以下命令:
kubectl proxy --port=8001 --address=0.0.0.0 --accept-hosts='^.*'
由於是虛擬機環境,只能是虛擬機所在的機器才能打開 需要做虛擬機端口映射,
本虛擬機的請忽略此步驟!
做了本機端口到虛擬機的端口映射之后,
打開你本機瀏覽器直接訪問虛擬機的k8s的控制面板
注意我上面用的k8s proxy是8001端口,url如下:
http://<本機IP>:8001/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/#/service?namespace=default
打開如下圖:
寫一個demo應用然后部署到k8s
demo就是一個自帶的的天氣預報的webapi模板。
然后創建成功后 需要更改一處代碼(看注釋):
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger) {
_logger = logger;
}
[HttpGet]
public IEnumerable<WeatherForecast> Get() {
//這里加下獲取本機ip,因為到時候部署到k8s我們得確認是不是訪問的ip會變化
var feature = HttpContext.Features.Get<IHttpConnectionFeature>();
string LocalIPAddr = feature?.LocalIpAddress?.ToString() ?? "unknow";
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
//到時候候我們確認這個字段即可
Summary = LocalIPAddr
})
.ToArray();
}
}
然后把這個demo應用創建一個鏡像並推送到dockerhub倉庫,
這里我使用我的開源工具AntDeploy來一鍵推送。
這個工具使用教程可以查看我之前寫的
[開源]制作docker鏡像不依賴linux和Docker環境
工具的背后原理可以查看:
Docker鏡像構建原理解析(不裝docker也能構建鏡像)
我把這個demo傳到了dokcerHub鏡像的地址:nainaigu/k8s-demo:1.8
1. Deployment的使用
Deployment的作用是定義及管理多副本應用(即多個副本 Pod)
如果Pod出現故障,對應的服務也會掛掉,所以Kubernetes提供了一個Deployment的概念,
目的是讓Kubernetes去管理一組Pod的副本,也就是副本集,
這樣就能夠保證一定數量的副本一直可用,不會因為某一個Pod掛掉導致整個服務掛掉。
編寫Deployment的yml文件
apiVersion: apps/v1 // 指定版本,支持的版本可以通過kubectl api-versions查詢
kind: Deployment //固定 指定類型,這一次我們要創建一個Deployment
metadata: #元數據
name: k8s-demo //delpoyment的名稱,必須在deployment中保持唯一
labels:
name: k8s-demo //反正所有標簽都一個名字
spec: //deployment的詳細內容
replicas: 2 //容器2個副本pod
selector: //選擇器
matchLabels:
name: k8s-demo //選擇label中的name=k8s-demo的
template:
metadata:
labels:
name: k8s-demo //指定一個label名為name,值為k8s-demo,對應上面的selector
spec:
containers:
- name: k8s-demo //容器名
image: nainaigu/k8s-demo:1.8 //鏡像地址
imagePullPolicy: IfNotPresent //如果本地沒有鏡像就去倉庫pull
ports:
- containerPort: 5000 //容器暴露的端口
env: //環境變量
- name: "ASPNETCORE_URLS"
value: "http://0.0.0.0:5000"
上面的配置的意思就是:
- 從鏡像倉庫拉取你的鏡像
- 配置你的鏡像啟動的參數,暴露的端口等
- 給你這個服務起個名字並且打上標簽,執行后會有2個pod(服務實例)
接下來把這個配置保存為k8s-demo.yml 上傳到虛擬機然后敲命令裝配到k8s
//創建
kubectl create -f k8s-demo.yaml
//查看,后面想看某個pod的啟動日志 也需要先找到pod名稱
kubectl get pod -l name=k8s-demo
然后在k8s面板上查看
2. Service的使用和創建
k8s Service定義了這樣一種抽象: Service是一種可以訪問 Pod邏輯分組的策略, Service通常是通過 Label Selector訪問 Pod組(等下在寫service的yml文件就能看出來了)
Service的出現,可以解決每次Deployment的時候ip會換的問題
不過Service只支持4層的負載均衡,不支持7層(k8s是用Ingress來支持7層)。
當Pod宕機后重新生成時,其IP等狀態信息可能會變動,
Service會根據Pod的Label對這些狀態信息進行監控和變更,保證上游服務不受Pod的變動而影響
Service在 K8s中有常見的以下幾種類型:
- ClusterIp <只能是集群內部訪問,可以通過proxy讓外部訪問>
- NodePort <nodeport來暴露服務讓外部訪問>
- LoadBalancer <生產環境一般都是使用LoadBalancer的方式>
apiVersion: v1
kind: Service
metadata:
name: k8s-demo
spec:
selector: //篩選pod。上面創建Deployment的時候指定了
name: k8s-demo
type: ClusterIP //只能k8s集群內部訪問,外部網絡不能夠訪問到
ports:
- protocol: TCP
port: 5000 //k8s集群內部通過 5000 端口來訪問 下面的
targetPort: 5000 //容器暴露端口,與Dockerfile暴露端口保持一致
上面的Service配置表示:
- 創建了一個名叫k8s-demo的Service
- 用來訪問上面我們Deployment創建的一組name=k8s-demo的Pods
- 不管你Deployment后面是重新發布還是擴容還是縮容,不管怎么變化,只要通過Service暴露的端口就能負載均衡的訪問到那一組 Pods
- 我們設置的類型是ClusterIP,默認是k8s集群內部可訪問,但是也可以通過k8s的proxy功能來訪問
如果是NodePort(可以集群外訪問)的話要需要按照如下規則來配置
apiVersion: v1
kind: Service
metadata:
name: k8s-demo
spec:
selector: //篩選pod。上面創建Deployment的時候指定了
name: k8s-demo
type: NodePort //配置為NodePort,外部可以訪問,要定義下面的nodePort參數
ports:
- protocol: TCP
port: 5000 //k8s集群內部通過 5000 端口來訪問 下面的
targetPort: 5000 //容器暴露端口,與Dockerfile暴露端口保持一致
nodePort: 30001 // NodePort,外部訪問的端口來訪問上面的targetPort
總結這2種的區別就是:
集群內 serviceip:容器端口。 集群外: 宿主機IP:nodePort端口
我們按照第一種方式(type: ClusterIP)測試
查看下service的ip:10.105.108.92
由於是集群內部才能訪問,所以先用下面的命令進入minikube搭建的k8s集群內部環境
minikube ssh
curl http://10.105.108.92:5000/WeatherForecast
訪問服務成功!!
在外部網絡可以使用k8s的proxy來訪問
http://10.32.104.164:8001/api/v1/namespaces/default/services/k8s-demo:5000/proxy/WeatherForecast
注意通過proxy訪問的url拼接的規范:
- k8s-demo:5000 代表你創建的service的名稱和端口
- /WeatherForecast 代表你服務暴露的接口
ConfigMap的使用
ConfigMap 就是為了讓鏡像 和 配置文件解耦。好比一個動態的數據源,你創建后可以在
創建Deployment的時候指定用它。然后你想要動態更新,容器內也能監聽到文件內容更改,進行熱重載!
k8s的另外一個類似的功能叫secret,Secret類似於ConfigMap,是用Base64加密,密文顯示,一般存放敏感數據!
下面創建一個appsettings.json的configMap
apiVersion: v1
kind: ConfigMap
metadata:
name: appsettings
data:
appsettings.json: |-
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"Settings": {
"Message": "The configuration is working!"
}
}
然后改下demo應用
這里單獨搞了一個Settings的目錄來保存配置文件。
然后在api里面讀出來配置的Settings.Message信息
這里注意有一個坑 :netcore中的默認的機制是監聽配置文件的lastChangetime,
但是configMap變更后居然不會有任何變化(因為它是符號連接(symbolic link)),所以需要自己寫一個watch來適配,詳細可以看demo中的代碼!
下面來測試下效果:
第一步:把configMap創建到k8s中
第二步:先刪除掉上面創建的Deployment和Service
第三步:在Deployment的配置中用configMap
第四步:重新創建Deployment和Service
以上四步可以一次性搞定,
k8s的yml可以把Deployment和Service和configMap全放在一個yml文件:
apiVersion: apps/v1
kind: Deployment
metadata:
name: k8s-demo
labels:
name: k8s-demo
spec:
replicas: 2
selector:
matchLabels:
name: k8s-demo
template:
metadata:
labels:
name: k8s-demo
spec:
containers:
- name: k8s-demo
image: nainaigu/k8s-demo:1.8
imagePullPolicy: IfNotPresent
ports:
- containerPort: 5000
env:
- name: "ASPNETCORE_URLS"
value: "http://0.0.0.0:5000"
volumeMounts:
- name: appsettings-volume
mountPath: "/publish/Settings" //這里用configMap
volumes:
- name: appsettings-volume
configMap:
name: appsettings //這里用configMap
---
apiVersion: v1
kind: Service
metadata:
name: k8s-demo
spec:
selector:
name: k8s-demo
type: ClusterIP
ports:
- protocol: TCP
port: 5000
targetPort: 5000
---
apiVersion: v1
kind: ConfigMap
metadata:
name: appsettings
data:
appsettings.json: |-
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"Settings": {
"Message": "The configuration is working!"
}
}
如上圖,一個yml創建了configMap,Service,Deployment。
創建完成后,看下k8s面板:
通過proxy訪問下我們的demo服務:
由於我們在Deployment指定replicas:2個pod,訪問服務會負載均衡,ip會切換。
配置讀取的configmap信息是默認的 “The configuration is working!”
下面我們動態修改下configMap,來測試下demo應用會不會重新加載!
然后在來訪問下demo服務
確實加載到了新的配置了!
補充一些常用的命令:
查看部署的歷史記錄:
kubectl rollout history deployment.apps/k8s-demo
回滾 :kubectl rollout undo
比如回滾到上一個:
kubectl rollout undo deploy/k8s-demo
回滾到指定的版本:
kubectl rollout undo deploy/k8s-demo —to-revision=2
指定的版本可以通過歷史記錄的Revision字段
擴縮容kubectl scale
kubectl scale deployment k8s-demo —replicas=2
也可以在面板上操作
把2個實例 擴容到3個實例:
也可以設置達到某個條件自動擴容:
kubectl autoscale deployment k8s-demo —min=10 —max=20 —cpu-precent=70
代表最低10個實例,一旦cpu超過70% 自動觸發擴容 最大擴容到20個實例
查看Deployment的容器啟動日志 kubectl logs
demo應用的源碼:
https://github.com/yuzd/envoytest