Kubernetes系列之:將應用發佈到k8s(.Net Core與Go)

K8s上的應用是通過docker來布屬的,所以要將應用發佈到 K8s,前題是將應用製作成docker鏡像,並上傳到倉庫。

環境說明

# kubectl get nodes -o wide
NAME       STATUS   ROLES    AGE   VERSION   INTERNAL-IP     EXTERNAL-IP   OS-IMAGE                KERNEL-VERSION               CONTAINER-RUNTIME
k8s-0001   Ready    master   10d   v1.17.2   192.168.1.26    <none>        CentOS Linux 7 (Core)   3.10.0-1062.1.1.el7.x86_64   docker://1.13.1
k8s-0002   Ready    <none>   10d   v1.17.2   192.168.1.100   <none>        CentOS Linux 7 (Core)   3.10.0-1062.1.1.el7.x86_64   docker://1.13.1
k8s-0003   Ready    <none>   10d   v1.17.2   192.168.1.85    <none>        CentOS Linux 7 (Core)   3.10.0-1062.1.1.el7.x86_64   docker://1.13.1
k8s-0004   Ready    <none>   10d   v1.17.2   192.168.1.117   <none>        CentOS Linux 7 (Core)   3.10.0-1062.1.1.el7.x86_64   docker://1.13.1

項目爲最簡單的webapi項目,該示例中監聽了端口:5289

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseUrls("http://0.0.0.0:5289")
                .UseStartup<Startup>();
  • 製做、上傳鏡像並布屬到k8s
    1. 打開VS Code,同時按下 Command+ Shift+P;
    2. 點擊“>Docker:AddDocker Files to Workspace...”
    3. 選擇“ASP Net Core”,將自動創建DockerFile.內容如下:

注:如果是Go的應用通過自動創建的DockerFile,在運行時會報錯權限不足的錯誤,需重新編寫。點此查看《DockerFile詳解》

FROM mcr.microsoft.com/dotnet/core/aspnet:2.1 AS base
WORKDIR /app
EXPOSE 5289

FROM mcr.microsoft.com/dotnet/core/sdk:2.1 AS build
WORKDIR /src
COPY ["test.webapi.csproj", "./"]
RUN dotnet restore "./test.webapi.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "test.webapi.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "test.webapi.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "test.webapi.dll"]

從桌面上打開Docker(註冊帳號並登錄,所創建的倉庫將上傳至自已的帳號),運行後在右上角會有一個docker的icon

回到VS Code打開控制檯,通過docker build打包項目

$ docker build -t fengyily/webapi:v1 .
Sending build context to Docker daemon  32.26kB
Step 1/16 : FROM mcr.microsoft.com/dotnet/core/aspnet:2.1 AS base
 ---> d27433e73f8b
Step 2/16 : WORKDIR /app
 ---> Using cache
 ---> d21b3b3634cf
Step 3/16 : EXPOSE 5289
 ---> Using cache
 ---> 86f2dc533d61
Step 4/16 : FROM mcr.microsoft.com/dotnet/core/sdk:2.1 AS build
 ---> be2b589b3992
Step 5/16 : WORKDIR /src
 ---> Using cache
 ---> 4d1c285b0dd2
Step 6/16 : COPY ["test.webapi.csproj", "./"]
 ---> Using cache
 ---> bb804e07f792
Step 7/16 : RUN dotnet restore "./test.webapi.csproj"
 ---> Using cache
 ---> 8bb314beb77e
Step 8/16 : COPY . .
 ---> 38bc90ce9a67
Step 9/16 : WORKDIR "/src/."
 ---> Running in 33e3305ccfc4
Removing intermediate container 33e3305ccfc4
 ---> f510bc0df788
Step 10/16 : RUN dotnet build "test.webapi.csproj" -c Release -o /app/build
 ---> Running in 51773af168d9
Microsoft (R) Build Engine version 16.2.37902+b5aaefc9f for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

  Restore completed in 597.56 ms for /src/test.webapi.csproj.
  test.webapi -> /app/build/test.webapi.dll

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:05.52
Removing intermediate container 51773af168d9
 ---> 8f77e942d5e2
Step 11/16 : FROM build AS publish
 ---> 8f77e942d5e2
Step 12/16 : RUN dotnet publish "test.webapi.csproj" -c Release -o /app/publish
 ---> Running in e7750061499d
Microsoft (R) Build Engine version 16.2.37902+b5aaefc9f for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

  Restore completed in 55.3 ms for /src/test.webapi.csproj.
  test.webapi -> /src/bin/Release/netcoreapp2.1/test.webapi.dll
  test.webapi -> /app/publish/
Removing intermediate container e7750061499d
 ---> fcbc2fac2f29
Step 13/16 : FROM base AS final
 ---> 86f2dc533d61
Step 14/16 : WORKDIR /app
 ---> Using cache
 ---> 477f20371de1
Step 15/16 : COPY --from=publish /app/publish .
 ---> Using cache
 ---> 9a9914a4a6e6
Step 16/16 : ENTRYPOINT ["dotnet", "test.webapi.dll"]
 ---> Using cache
 ---> 2e2ac48eb92e
Successfully built 2e2ac48eb92e
Successfully tagged fengyily/webapi:v1

通過後可運行docker run fengyily/findo.api:v1來測試鏡像是否可用

測試通過後,將鏡像上傳至倉庫

$ docker push fengyily/webapi:v1
The push refers to repository [docker.io/fengyily/webapi]
7ff696383b4c: Layer already exists 
4854b085f893: Layer already exists 
977691ddf529: Layer already exists 
217f610b769d: Mounted from fengyily/findo 
f19669fee5cc: Layer already exists 
e0db3ba0aaea: Layer already exists 
v1: digest: sha256:068ba4453ff88d8d7bb81940536405efbb1afb2fd1dd029325bba275e6e166d1 size: 1580

上傳成功,接下來我們就編寫webapi的yaml,布屬至K8s集羣中。

在k8s上創建develop名稱空間

kubectl create ns develop

testwebapi.yaml

# cat testwebapi.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    webapi: testwebapi
  name: testapi
  namespace: develop
spec:
  replicas: 2
  selector:
    matchLabels:
      webapi: testwebapi
  template:
    metadata:
      labels:
        webapi: testwebapi
    spec:
      containers:
      - name: testwebapi
        image: fengyily/webapi:v1
        imagePullPolicy: Always
        ports:
        - containerPort: 5289
        livenessProbe:
          httpGet:
            path: /api/values
            port: 5289
            httpHeaders:
            - name: X-Custom-Header
              value: Awesome
          initialDelaySeconds: 5
          periodSeconds: 5

testwebapi-svc.yaml

# cat testwebapi-svc.yaml 
apiVersion: v1
kind: Service
metadata:
  name: testapi
  namespace: develop
spec:
  ports:
    - protocol: TCP
      port: 8889
      targetPort: 5289
      name: web
  selector:
    webapi: testwebapi

通過kubectl apply -f .  一次性創建好

# kubectl apply -f .
service/testapi 
deployment.apps/testapi 

檢查一下,基中testapi開頭的是通過剛纔制到的鏡像布屬的,go開頭的是go開發的應用,下一節將講解如何訪問k8s中的應用。

[root@k8s-0001 myapp]# kubectl get pods -n develop -o wide
NAME                                        READY   STATUS    RESTARTS   AGE    IP            NODE       NOMINATED NODE   READINESS GATES
testapi-85664b498-vl749                     1/1     Running   0          8d     10.244.2.13   k8s-0002   <none>           <none>
testapi-85664b498-zxqml                     1/1     Running   5          9d     10.244.3.13   k8s-0004   <none>           <none>
go-findo-api-55c8ddd98d-cb2h8               1/1     Running   0          13h    10.244.2.26   k8s-0002   <none>           <none>
go-findo-api-55c8ddd98d-pmpd8               1/1     Running   0          13h    10.244.1.43   k8s-0003   <none>           <none>
go-findo-api-55c8ddd98d-vmgvz               1/1     Running   0          12h    10.244.3.22   k8s-0004   <none>           <none>

[root@k8s-0001 myapp]# kubectl get svc -n develop -o wide
NAME                       TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE    SELECTOR
default-http-backend       ClusterIP   10.102.58.113    <none>        80/TCP                       6d9h   app.kubernetes.io/name=default-http-backend,app.kubernetes.io/part-of=ingress-nginx
findo-svc                  ClusterIP   10.102.47.86     <none>        6660/TCP                     6d9h   webapi=findo-api
go-findo-svc               ClusterIP   10.108.8.131     <none>        8080/TCP                     28h    webapi=go-findo-api
nginx-ingress-controller   NodePort    10.101.0.193     <none>        80:30033/TCP,443:30241/TCP   6d9h   app.kubernetes.io/name=ingress-nginx
testapi                    ClusterIP   10.108.208.200   <none>        8889/TCP                     6d8h   webapi=testwebapi

Go 應用對應的DockerFile,示例一:簡單實現,是將源碼COPY至鏡像,然後編譯運行,這樣的鏡像會非常大,實際上我們只需將編譯結果複製。


FROM golang:latest
ENV GO111MODULE on
WORKDIR /app
USER root
COPY . .
RUN go build main.go

CMD ["./main"]

 

示例二:已做優化

#build stage
FROM golang:alpine AS builder
WORKDIR /go/src/app
COPY . .
RUN go clean -cache
ENV GO111MODULE on
ENV GIN_MODE release
RUN go build -o /go/bin/app /go/src/app/main.go

#final stage
FROM alpine:latest
USER root
RUN apk add ca-certificates
COPY --from=builder /go/bin/app /app
COPY ./conf/app.ini.bak ./conf/app.ini
COPY ./views ./views

ENTRYPOINT ./app
LABEL Name=go.findo.api Version=0.0.1
EXPOSE 8080

優化主要爲以下兩點:

1、基礎系統採用alpine版本,只有 5M左右,golang:latest有 200M左右

2、編譯後,將編譯的文件、配置、視圖拷貝至鏡像(源代碼+框架+引用源碼:61M

我們來看一下優化前後鏡像的大小,以及基礎OS的大小

以下是同一go應用採用不同基礎系統鏡大小的差異,可以看出基於alpine版的鏡像只有 23M,golang的alpine版 483M,latest版 927M
fengyideMacBook-Pro:~ fengyi$ docker images
REPOSITORY                             TAG		OS                				 IMAGE ID            CREATED            		 SIZE
fengyily/go.findo.api                  auto 	       FROM alpine:latest     0d43ec73a46a        32 seconds ago      23.1MB
fengyily/go.findo.api                  alpine 	       FROM golang:alpine            9aa dd792eef2        7 hours ago         483MB
fengyily/go.findo.api                  v1                FROM golang:latest   	   3a3508748fe2        8 hours ago         927MB

以下是net core應用鏡像大小(未優化)
REPOSITORY                         TAG		 IMAGE ID            CREATED            		 SIZE
fengyily/findo                         v1                  099e276b2b89        10 days ago         264MB
fengyily/webapi                      v1                  2e2ac48eb92e        10 days ago         254MB
f1api/test.webapi                    v1                  bd056e05c29e        12 days ago         254MB
mcr.microsoft.com/dotnet/core/sdk      2.1                 be2b589b3992        12 days ago         1.74GB
mcr.microsoft.com/dotnet/core/aspnet   2.1                 d27433e73f8b        12 days ago         253MB

以下是各系統的基礎鏡像大小
REPOSITORY                         TAG		 IMAGE ID            CREATED            	   SIZE
debian                                 latest              a8797652cfd9        12 days ago         114MB
golang                                 alpine              87eefb76f0a8        2 weeks ago         359MB
golang                                 latest              6586e3d10e96        11 days ago         803MB
alpine                                  latest              e7d92cdc71fe        3 weeks ago           5.59MB

可以看出,採用alpine系統以及只差編譯後文件打包後,最終鏡像的大小爲 23.1M。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章