记一次aspnetcore发布部署流程初次使用k8s

aspnetcore,k8s · 浏览次数 : 56

小编点评

本文介绍了如何将ASP.NET Core Web API项目部署到Kubernetes(K8s)并使用GitLab的持续集成/持续部署(CI/CD)流程。整个过程包括编写Dockerfile、k8s.yaml文件,以及配置GitLab CI/CD和Jenkins。以下是详细的步骤和配置说明: ### 1. 准备工作 - 创建一个新的ASP.NET Core Web API项目,并确保项目中的Swagger非开发环境不展示。 - 安装Docker和GitLab CI/CD。 - 准备Dockerfile和k8s.yaml文件。 ### 2. 编写Dockerfile ```Dockerfile # 使用官方的ASP.NET Core镜像作为基础镜像 FROM mcr.microsoft.com/dotnet/aspnet:5.0-buster-slim AS base # 将当前目录的内容复制到容器的工作目录 COPY . /app # 暴露5000端口 EXPOSE 5000/tcp # 设置环境变量 ENV ASPNETCORE_URLS http://*:5000/ ENV TZ=Asia/Shanghai # 安装System.Drawing native dependencies RUN apt-get update && \ apt-get install -y --allow-unauthenticated ca-certificates libgdiplus && \ rm -rf /var/lib/apt/lists/* # 设置入口点 ENTRYPOINT ["dotnet", "autopubtest.dll"] ``` ### 3. 编写k8s.yaml文件 ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: {deployName} labels: app: {deployName} namespace: default spec: replicas: 2 selector: matchLabels: app: {deployName} template: metadata: labels: app: {deployName} spec: nodeSelector: group: web containers: - name: {containerName} image: {imageRegistry}/{imageName}:{imageTag} volumeMounts: - name: config-volume mountPath: /app/appsettings.Production.json subPath: appsettings.Production.json env: - name: ASPNETCORE_ENVIRONMENT value: Production ports: - containerPort: 5000 volumes: - name: config-volume configMap: name: autopubtest-config --- apiVersion: v1 kind: Service metadata: name: {serviceName} labels: app: {serviceName} namespace: default spec: selector: app: {deployName} ports: - name: {serviceName} port: 5000 protocol: TCP targetPort: 5000 ``` ### 4. 配置GitLab CI/CD - 在项目根目录下创建.gitlab-ci.yml文件。 - 添加以下内容: ```yaml stages: - build - test - deploy build-job: stage: build tags: - docker - linux script: - echo "Compiling the code..." - echo "Compile complete." unit-test-job: stage: test tags: - docker - linux script: - echo "Running unit tests..." - sleep 60 - echo "Code coverage is 90%" lint-test-job: stage: test tags: - docker - linux script: - echo "Linting code..." - sleep 10 - echo "No lint issues found." deploy-job: stage: deploy tags: - docker - linux environment: production script: - echo "Deploying application..." - echo "Application successfully deployed." ``` ### 5. 配置Jenkins - 安装GitLab CI/CD插件。 - 在Jenkins中创建一个新的任务,选择“Pipeline”类型。 - 在“源代码管理”部分,选择“GitLab”。 - 在“构建触发器”部分,选择“GitHub hook trigger for GITScm polling”。 - 在“分支”部分,勾选“Only code changes”。 - 在“构建环境”部分,选择“Docker”。 - 在“Post-build Actions”部分,添加“Build an image”动作,设置镜像名称和标签。 - 在“推送镜像到 registry”部分,设置镜像仓库和端口。 - 在“部署”部分,添加“Kubernetes”配置,指定Kubernetes API服务器地址、用户名、密码和集群名。 - 在“验证”部分,选择“构建成功后部署”。 完成上述配置后,Jenkins将自动构建、测试和部署ASP.NET Core Web API项目到Kubernetes集群。 ### 6. 配置Harbor - 在GitLab CI/CD的`.gitlab-ci.yml`文件中,将`imageRegistry`设置为Harbor仓库的地址。 - 在Jenkins的`.jenkins/config.xml`文件中,配置SSH密钥,以便Jenkins能够访问Harbor仓库。 - 在Kubernetes的`values.yaml`文件中,将`imageRegistry`设置为Harbor仓库的地址。 完成上述配置后,Harbor将作为镜像仓库,用于存储和推送ASP.NET Core Web API项目的镜像。 以上就是将ASP.NET Core Web API项目部署到Kubernetes并使用GitLab的CI/CD流程的方法。在实际操作中,可能需要进行一些调整和优化,以满足特定的需求和环境。

正文

主题:

aspnetcorewebapi项目,提交到gitlab,通过jenkins(gitlab的ci/cd)编译、发布、推送到k8s。

关于gitlab、jenkins、k8s安装,都是使用docker启动服务。

首先新建一个项目,为了方便浏览就把swaggerr非开发环境不展示去掉

 

下面就是需要准备Dockerfile和k8s.yaml文件,这里不应该用net5,过时了。

FROM mcr.microsoft.com/dotnet/aspnet:5.0-buster-slim AS base
COPY . /app
WORKDIR /app
EXPOSE 5000/tcp
ENV ASPNETCORE_URLS http://*:5000/
ENV TZ=Asia/Shanghai

# Work around for broken dotnet restore
ADD http://ftp.us.debian.org/debian/pool/main/c/ca-certificates/ca-certificates_20210119_all.deb .
RUN dpkg -i ca-certificates_20210119_all.deb

# soft link
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN ln -s /lib/x86_64-linux-gnu/libdl-2.24.so /lib/x86_64-linux-gnu/libdl.so

# install System.Drawing native dependencies
RUN apt-get update \
    && apt-get install -y --allow-unauthenticated \
    ca-certificates \
    && update-ca-certificates \
                libgdiplus \
     && rm -rf /var/lib/apt/lists/*
     
ENTRYPOINT ["dotnet", "autopubtest.dll"]

 

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {deployName}
  labels:
    app: {deployName}
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: {deployName}
  template:
    metadata:
      labels:
        app: {deployName}
    spec:
      nodeSelector:
        group: web
      containers:
      - name: {containerName}
        image: {imageRegistry}/{imageName}:{imageTag}
        volumeMounts:
        - name: config-volume
          mountPath: /app/appsettings.Production.json
          subPath: appsettings.Production.json
        env:
        - name: ASPNETCORE_ENVIRONMENT
          value: Production
        ports:
        - containerPort: 5000
      volumes:
      - name: config-volume
        configMap:
          name: autopubtest-config
      imagePullSecrets:
      - name: docker-secret
---

kind: Service
apiVersion: v1
metadata:
  name:  {serviceName}
  labels:
    app:  {serviceName}
  namespace: default
spec:
  selector:
    app:  {deployName}
  ports:
  - name:  {serviceName}
    port: 5000
    protocol: TCP
    targetPort: 5000

这里需要注意的是configMap的name是我们需要再K8S里面建的appsettings.环境.json文件

  configMap:
          name: autopubtest-config

  

 一切准备就绪,本地需要有docker环境,就能验证dockerfile是否有报错,我本地是dockerdesktop。

下面就先把代码提交到gitlab,我是用develop自建分支,而且我用的是http

 这里gitlab

v17.1.1

有一个问题就是默认会把容器的id当成请求的ip地址,通过git 的git或者http拉取代码这里都会有问题,进入gitlab的容器内部找到 /etc/gitlab/gitlab.rb找到external_url注释掉的一行,改下你实际的地址和端口就行。

 这里稍微提一下gitlab的ci/cd,本篇主要是jenkins。

gitlab安装完默认密码存放在 /etc/gitlab/initial_root_password ,默认用户root

networks:指定唯一,在服务器中新建一个networks,方便一个网段通信,如果是分开的服务器就是用ip或者其他。
register runner的时候手敲,ip指定gitlab容器的内网ip,查看命令 docker inspect docker容器id,类似这样的,下面提示就是成功注册一个runner
Registering runner... succeeded                     runner=
gitlab-runner register \
  --url http://gitlab的docker的ip \
  --registration-token gitlab runners中的token \
  --executor docker \
  --description "My Docker Runner" \
  --docker-image "alpine:latest"
这里是安装gitlab和gitlab-runner的docker-compose.yml 
version: '3.3'
services:
  gitlab:
    image: gitlab/gitlab-ce:latest
    container_name: gitlab
    ports:
      - "80:80"
    networks:
      - my-network

  gitlab-runner:
    image: gitlab/gitlab-runner:latest
    container_name: gitlab-runner
    restart: always
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    networks:
      - my-network

networks:
  my-network:
    driver: bridge

 

只要在项目中新增.gitlab-ci.yml,再把类似jenkins的shell操作放到文件中就可以了。这里有一个测试的文件,tags很重要,注册runner的时候指定需要的,再在文件中配置了,就会按照流程。

stages:          # List of stages for jobs, and their order of execution
  - build
  - test
  - deploy

build-job:       # This job runs in the build stage, which runs first.
  stage: build
  tags:           # Add the tags here
    - docker
    - linux
  script:
    - echo "Compiling the code..."
    - echo "Compile complete."

unit-test-job:   # This job runs in the test stage.
  stage: test    # It only starts when the job in the build stage completes successfully.
  tags:           # Add the tags here
    - docker
    - linux
  script:
    - echo "Running unit tests... This will take about 60 seconds."
    - sleep 60
    - echo "Code coverage is 90%"

lint-test-job:   # This job also runs in the test stage.
  stage: test    # It can run at the same time as unit-test-job (in parallel).
  tags:           # Add the tags here
    - docker
    - linux
    - fast
  script:
    - echo "Linting code... This will take about 10 seconds."
    - sleep 10
    - echo "No lint issues found."

deploy-job:      # This job runs in the deploy stage.
  stage: deploy  # It only runs when *both* jobs in the test stage complete successfully.
  tags:           # Add the tags here
    - docker
    - linux
    - fast
  environment: production
  script:
    - echo "Deploying application..."
    - echo "Application successfully deployed."

 

上面仅仅只是一个测试完整流程文件,不涉及docker打包操作,需要docker打包的话runner就需要安装,安装模式有几种,自行查资料。

 

下面介绍jenkins的操作

 

 

 这里提一提,通过git拉取代码,需要在jenkins的容器内部生成.ssh的公钥私钥,公钥添加到gitlab的ssh中,私钥就放到jenkins的全局变量中,Credentials就可以选择你的验证方式了。

下面的选择会影响你拉取代码,第一个设置你有可能需要在jenkins容器内部拉取一次代码,最后一个设置可以通过http拉。

 

 下面继续:

 

 这里我有三个步骤,编译,发布,K8S拉取镜像

第一部分

#!/bin/bash

echo "==========  当前 Branch: $GIT_BRANCH  =========="
echo "==========  Commit Hash: $GIT_COMMIT  =========="

cd $WORKSPACE/src/autopubtest/
  dotnet restore 

if [ -d $WORKSPACE/publish ]; then
    rm -rf $WORKSPACE/publish
fi

dotnet publish -c Release -o $WORKSPACE/publish --no-restore

if [ $? -ne 0 ]; then
  echo "!!!!!!!!!!编译失败!!!!!!!!!!"
  exit 1
else
  echo "<<<<<<<<<<编译成功>>>>>>>>>>"
fi


第二部分

#!/bin/bash
ob=`echo $jobName|tr 'A-Z' 'a-z'|cut -d '.' -f 2`
imageName="autopubtest-api"
#imageTag=$TagName
imageTag=`echo "$GIT_COMMIT" | cut -b1-8`
pushRegistry=镜像仓库/项目名
    
echo "==========  开始构建镜像 =========="

docker login -u 仓库账号 -p 仓库密码 $pushRegistry
cd $WORKSPACE/publish
docker build --rm -t $imageName:$imageTag -f $WORKSPACE/docker/Dockerfile .

if [ $? -ne 0 ]; then
  echo "!!!!!!!!!!镜像构建失败!!!!!!!!!!"
  exit 1
else
  echo "<<<<<<<<<<镜像构建成功 $imageName:$imageTag>>>>>>>>>>"
fi

                                        
docker tag $imageName:$imageTag $pushRegistry/$imageName:$imageTag
docker push $pushRegistry/$imageName:$imageTag

if [ $? -ne 0 ]; then
  echo "!!!!!!!!!!镜像发布失败!!!!!!!!!!"
  exit 1
else
  echo "<<<<<<<<<<镜像发布成功 $imageName:$imageTag>>>>>>>>>>"
fi

docker rmi $imageName:$imageTag
docker rmi $pushRegistry/$imageName:$imageTag


第三部分

projectName="autopubtest-api"
#imageTag=$TagName
imageTag=`echo "$GIT_COMMIT" | cut -b1-8`
deployName=$projectName
serviceName=$projectName
containerName=$projectName
imageName=$projectName
git_message=`git log --format=format:%s -1 ${GIT_COMMIT}`
pullRegistry=仓库地址/项目名

cat $WORKSPACE/docker/k8s.yaml | sed 's|'extensions/v1beta1'|'apps/v1'|g; s|{imageRegistry}|'$pullRegistry'|g; s|{imageName}|'$imageName'|g; s|{imageTag}|'$imageTag'|g; s|{deployName}|'$deployName'|g; s|{serviceName}|'$serviceName'|g; s|{containerName}|'$containerName'|g' > $WORKSPACE/docker/k8s.value
sed -i '/^---/,$d' $WORKSPACE/docker/k8s.value

kubectl      apply -f $WORKSPACE/docker/k8s.value 
if [ $? -ne 0 ]; then
  echo "!!!!!!!!!!更新失败,Deployment $deployName 可能不存在,尝试创建该Deployment!!!!!!!!!!"
  kubectl      create -f $WORKSPACE/docker/k8s.value 
fi

 

构建的日志就略过,这里使用的是harbor仓库,注需要注意,docker login需要登陆harbor的仓库,在harbor主机host通过ip地址映射一个随意取名的域名,不要用ip,否则触发https安全检查。

 jenkins的第三步,会触发k8s去pull仓库镜像。关于jenkins和k8s的关联就是把k8s主机的config文件拷贝到jenkins的 ./var/jenkins_home/root/.kube/config

当K8S拉取镜像后,服务正常启动。

 配置字典里新建autopubtest的appsettings.Production.json文件,该名称需要与k8s。yaml的对应起来autopubtest-config

 

新建下面的服务

 

 

 下面就能正常使用接口了

 

与记一次aspnetcore发布部署流程初次使用k8s相似的内容:

记一次aspnetcore发布部署流程初次使用k8s

主题: aspnetcorewebapi项目,提交到gitlab,通过jenkins(gitlab的ci/cd)编译、发布、推送到k8s。 关于gitlab、jenkins、k8s安装,都是使用docker启动服务。 首先新建一个项目,为了方便浏览就把swaggerr非开发环境不展示去掉 下面就是需

记一次 CDN 流量被盗刷经历

先说损失,被刷了 70 多RMB,还好止损相对即时了,亏得不算多,PCDN 真可恶啊。 600多G流量,100多万次请求。 怎么发现的 先是看到鱼皮大佬发了一篇推文突发,众多网站流量被盗刷!我特么也中招了。 抱着看热闹的心情点开阅读了。。。心想,看看自己的中招没,结果就真中招了 。 被盗刷资源分

记一次 .NET某上位视觉程序 离奇崩溃分析

一:背景 1. 讲故事 前段时间有位朋友找到我,说他们有一个崩溃的dump让我帮忙看下怎么回事,确实有太多的人在网上找各种故障分析最后联系到了我,还好我一直都是免费分析,不收取任何费用,造福社区。 话不多说,既然有 dump 来了,那就上 windbg 说话吧。 二:WinDbg 分析 1. 为什么

记一次 .NET某酒业业务系统 崩溃分析

一:背景 1. 讲故事 前些天有位朋友找到我,说他的程序每次关闭时就会自动崩溃,一直找不到原因让我帮忙看一下怎么回事,这位朋友应该是第二次找我了,分析了下 dump 还是挺经典的,拿出来给大家分享一下吧。 二:WinDbg 分析 1. 为什么会崩溃 找崩溃原因比较简单,用 !analyze -v 命

记一次 .NET某网络边缘计算系统 卡死分析

一:背景 1. 讲故事 早就听说过有什么 网络边缘计算,这次还真给遇到了,有点意思,问了下 chatgpt 这是干嘛的 ? 网络边缘计算是一种计算模型,它将计算能力和数据存储位置从传统的集中式数据中心向网络边缘的用户设备、传感器和其他物联网设备移动。这种模型的目的是在接近数据生成源头的地方提供更快速

记一次RocketMQ消费非顺序消息引起的线上事故

应用场景 C端用户提交工单、工单创建完成之后、会发布一条工单创建完成的消息事件(异步消息)、MQ消费者收到消息之后、会通知各处理器处理该消息、各处理器处理完后都会发布一条将该工单写入搜索引擎的消息、最终该工单出现在搜索引擎、被工单处理人检索和处理。 事故异常体现 1、异常体现 从工单的流转记录发现、

记一次难忘的json反序列化问题排查经历

前言 最近我在做知识星球中的商品秒杀系统,昨天遇到了一个诡异的json反序列化问题,感觉挺有意思的,现在拿出来跟大家一起分享一下,希望对你会有所帮助。 案发现场 我最近在做知识星球中的商品秒杀系统,写了一个filter,获取用户请求的header中获取JWT的token信息。 然后根据token信息

记一次 .NET某机械臂上位系统 卡死分析

一:背景 1. 讲故事 前些天有位朋友找到我,说他们的程序会偶发性的卡死一段时间,然后又好了,让我帮忙看下怎么回事?窗体类的程序解决起来相对来说比较简单,让朋友用procdump自动抓一个卡死时的dump,拿到dump之后,上 windbg 说话。 二:WinDbg 分析 1. 主线程在做什么 要想

记一次 .NET某工厂报警监控设置 崩溃分析

一:背景 1. 讲故事 前些天有位朋友在微信上丢了一个崩溃的dump给我,让我帮忙看下为什么出现了崩溃,在 Windows 的事件查看器上显示的是经典的 访问违例 ,即 c0000005 错误码,不管怎么说有dump就可以上windbg开干了。 二:WinDbg 分析 1. 程序为谁崩溃了 在 Wi

记一次 .NET某游戏币自助机后端 内存暴涨分析

一:背景 1. 讲故事 前些天有位朋友找到我,说他们的程序内存会偶发性暴涨,自己分析了下是非托管内存问题,让我帮忙看下怎么回事?哈哈,看到这个dump我还是非常有兴趣的,居然还有这种游戏币自助机类型的程序,下次去大玩家看看他们出币的机器后端是不是C#写的?由于dump是linux上的程序,刚好win