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。

Logo

开源、云原生的融合云平台

更多推荐