5000 字手把手实战|Kubernetes+极狐GitLab CI,获得极致 CI/CD 体验

news2024/12/27 19:47:48

目录

极狐GitLab CI + K8s 架构解析

极狐GitLab CI 流程图

流程详解

极狐GitLab CI + K8s 架构优点

开启极狐GitLab CI + K8s 实战

环境准备

记录注册信息

获取极狐GitLab Runner

绑定 docker.sock

配置缓存

安装极狐GitLab Runner

集成 CI

定义文件

注意事项

配置变量

运行测试

运行 Pipeline

查看运行 Pod

查看 Job

查看构建情况

注意事项

总结思考


本文来自:极狐GitLab 开发者社区

作者:KaliArch

微服务是一种以业务功能为主的服务设计概念,每一个服务都具有自主运行的业务功能,对外开放不受语言限制的 API,应用程序则是由一个或多个微服务组成。

在微服务架构中,不可变的基础设施和容器的自包含环境,使发布变得更加简单快捷,不用再考虑如何根据不同项目区分 Runner 环境;可以随时拉起一个 Pod 来运行我们的 Job,运行完成后立即销毁,不仅能实现动态运行节省资源,而且不用担心多项目多任务并发构建问题。

本文分享如何应用极狐GitLab CI 将应用发布进 K8s,适用于以下场景和人群:

  • 业务容器微服务化,或半微服务化;

  • 有明确流程规范,上线部署规范及明确可循的标准;

  • 追求极致持续集成/持续交付体验的 GitOps 追崇者;

  • 具备 K8s 运维能力的运维人员。

极狐GitLab CI + K8s 架构解析


本文以构建一个 Java 软件项目并将其部署到阿里云容器服务 K8s 集群中为例,说明如何使用极狐GitLab CI 在阿里云 K8s 服务上运行极狐GitLab Runner、配置 K8s 类型的 Executor,并执行 Pipeline。

极狐GitLab CI 流程图

流程详解

如上图为一个简单的极狐GitLab CI 部署进 K8s 流程图,同之前我们讲到的 CI 集成一致,只需要项目中存在 .gitlab-ci.yml 文件即可。

与之前的差异是,在集成 Kubernetes 时,gitlab-runner 运行在 K8s 内,其为一个 Pod 形式运行,控制着后续的 Pipeline 中各 Stage 执行。

可以看到,当一个 Pipeline 有多个 Stage,每个 Stage 都有一个单独的 Pod 去执行,这个 Pod 使用的镜像在 CI 的.gitlab-ci.yml 的每个 Stage 的 Image 中定义,如下所示为部署 Java 项目的流程:

  • 开发者或项目维护者 Merge Request 到特定分支,该分支存在 CI 文件,开始进行 CI;

  • CI  任务由已经注册在 gitlab-server 运行在 K8s 集群内的 gitlab-runner 进行下发:

    • 第一个为 Package,对 Java 项目利用 Maven 镜像进行打包,生成 War 包制品到缓存目录中;

    • 利用 Docker 镜像,根据项目中的 Dockerfile 对缓存中的制品进行镜像构建,构建完成后登录镜像仓库进行镜像推送;

    • 在此,将部署文件托管在项目内,也体现了 GitOps 思想,将之前构建推送成功的镜像地址信息在 deployment.yaml 文件进行修改,之后 Apply 进 k8s 中,Java 项目构建的镜像就运行在 K8s 集群内了,完成发布。

流程中有一些注意事项:

  • 可在 Stage 中添加自己业务需求的内容,例如单元测试、代码扫描等;

  • 在部署文件中,可以将整个项目制作成 Helm 的 Chart,替换其中的镜像,利用 Helm 来进行应用部署;

  • 应用部署中,单个 Stage 利用的是不同的 Image,在各个 Stage 中传递已经生成的制品例如 war/jar 包,需要使用外部存储来缓存制品。

极狐GitLab CI + K8s 架构优点


通过上面的极狐GitLab CI 流程,我们能够看到将极狐GitLab Runner 运行在 K8s 集群中,每个 Job 启动单独的 Pod 运行操作,此种方式完全凸显了 K8s 的优点:

  • 高可用:当某个节点出现故障时,K8s 会自动创建一个新的极狐GitLab Runner 容器,并挂载同样的 Runner 配置,使服务达到高可用;

  • 弹性伸缩:触发式任务,合理使用资源,每次运行脚本任务时,极狐GitLab Runner 会自动创建一个或多个新的临时 Runner 来运行 Job;

  • 资源最大化利用:动态创建 Pod 运行 Job,资源自动释放,而且 K8s 会根据每个节点资源的使用情况,动态分配临时 Runner 到空闲节点上,降低出现因某节点资源利用率高,还排队等待在该节点的情况;

  • 扩展性好:当 K8s 集群的资源严重不足而导致临时 Runner 排队等待时,可以很容易地添加一个 K8s Node 到集群中,从而实现横向扩展。

如果您的业务目前运行环境为 K8s,那么极狐GitLab CI 完全契合您的业务场景,您只需要自定义 gitlab-ci.yml 中的各个需求的 Stage 即可,配合 GitOps 将配置托管在项目内,跟随项目一起维护管理,实现端到端的 CI 工作流,使得运维工作也可通过 Git 追溯,提高工作效能,敏捷开发上线部署。

开启极狐GitLab CI + K8s 实战


通过上文内容,我们了解来极狐GitLab CI 与 K8s 的集成及其优点,接着,就让我们通过实战来更具体的了解其流程。

环境准备

  1. 极狐GitLab 服务器:可以是部署在物理服务器上,也可以部署在 K8s 集群内部;

  2. K8s 集群:可以是公有云的容器编排引擎,例如阿里云的 ACK、腾讯云的 TKE、华为云的CCE等都适用;

  3. 本次示例中使用 Helm 来安装,Helm 版本为 v2.14.3,有能力的伙伴,可以自己编写资源清单部署。

记录注册信息

登录极狐GitLab 服务器,记录极狐GitLab 的 URL 和注册令牌。

在部署进 K8s 的极狐GitLab Runnner 的配置中需要填写该信息,运行在 K8s 中的 Pod 就利用此信息在极狐GitLab 服务器进行注册。

获取极狐GitLab Runner

由于单独部署极狐GitLab Runner 进 K8s 中,自己去写资源清单文件难度较大且容易出错,我们在此利用官方 Chart 镜像通过 Helm 来进行部署,仅需修改其中我们关心的字段即可。

首先登录 K8s 集群,进行极狐GitLab Runner 的 Helm Repo 的添加;之后将 Chart 下载到本地,解压文件并修改其中的 values.yml 文件。

➤ 添加 Repo 获取 Charts

[root@master common-service]# helm repo add gitlab https://charts.gitlab.io
"gitlab" has been added to your repositories
[root@master common-service]# helm repo update
Hang tight while we grab the latest from your chart repositories...
...Skip local chart repository
...Successfully got an update from the "aliyun" chart repository
...Successfully got an update from the "apphub" chart repository
...Successfully got an update from the "gitlab" chart repository
...Successfully got an update from the "stable" chart repository
Update Complete.
[root@master common-service]# helm search gitlab-runner
NAME                    CHART VERSION   APP VERSION     DESCRIPTION  
gitlab/gitlab-runner    0.14.0          12.8.0          GitLab Runner

可以看到极狐GitLab Runner 的 Chart,其是 Helm 中描述相关的一组 K8s 资源文件集合,包含了一个 value.yaml 配置文件和一系列模板(deployment.yaml、svc.yaml 等)。

➤ 创建角色并绑定权限

极狐GitLab Runner 在运行时,需要访问 K8s 的 API。我们在此为其创建 ServiceAccount 并为其进行 RBAC 授权。

首先创建一个极狐GitLab Runner 的名称空间,并创建 Role,将 ServiceAccount 与 Role 进行绑定。

[root@master gitlab-runner]# cat > rbac-runner-config.yaml <<EOF
apiVersion: v1
kind: ServiceAccount                                                                                # 在gitlab-runners名称空间下创建名为gitlab的serviceaccount
metadata:
  name: gitlab
  namespace: gitlab-runners
---
kind: Role                                                                                                                                # 创建gitlab角色,
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: gitlab-runners
  name: gitlab
rules:
- apiGroups: [""] #"" indicates the core API group
  resources: ["*"]
  verbs: ["*"]
- apiGroups: ["apps"]                                                                
  resources: ["deployments"]
  verbs: ["*"]
- apiGroups: ["extensions"]
  resources: ["deployments"]
  verbs: ["*"]

---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: gitlab                                                                                                                                                # 将sa与角色进行绑定
  namespace: gitlab-runners
subjects:
- kind: ServiceAccount
  name: gitlab # Name is case sensitive
  apiGroup: ""
roleRef:
  kind: Role #this must be Role or ClusterRole
  name: gitlab # this must match the name of the Role or ClusterRole you wish to bind to
  apiGroup: rbac.authorization.k8s.io
  
EOF
# 创建资源清单
[root@master gitlab-runner]# kubectl create -f rbac-runner-config.yaml
serviceaccount/gitlab created
role.rbac.authorization.k8s.io/gitlab created
rolebinding.rbac.authorization.k8s.io/gitlab created

➤ 获取 Charts 文件,并进行配置

[root@master gitlab-runner]# helm fetch gitlab/gitlab-runner                                                
[root@master gitlab-runner]# tar xf gitlab-runner-0.14.0.tgz
[root@master gitlab-runner]# vim gitlab-runner/values.yaml 

Helm 为我们提供了一个配置文件,可以在安装 Runner 时,为其注册一个默认 Runner。我们可以去 gitlab-runner 的项目源码中获取到 values.yaml 这个配置文件。

绑定 docker.sock

由于在极狐GitLab Runner 中需要执行 docker build 命令,需要 Docker 服务端,我们可以绑定 K8s Node 节点的 docker.sock 来实现,编辑 Chart 下的 Template 目录中的 configmap.yaml,在大约 42 行修改。


# add volume and bind docker.sock
cat >>/home/gitlab-runner/.gitlab-runner/config.toml <<EOF
  [[runners.kubernetes.volumes.pvc]]
    name = "{{.Values.maven.cache.pvcName}}"
    mount_path = "{{.Values.maven.cache.mountPath}}"
  [[runners.kubernetes.volumes.host_path]]
    name = "docker"
    mount_path = "/var/run/docker.sock"
EOF

配置缓存

在流程详解中,能够看到生成的 war/jar 包制品需要存储在一个地方,这个地方就需要挂载一块外置的存储设备,在k8s 中,我们需要为其提供 PVC,如果你可以用 NFS 存储或者分布式 Ceph 制成的存储类。

在此,我们机器中使用的为 Storageclass,演示利用存储类来声明 PVC,在 Pod 中进行挂载。

➤ 创建 PVC 声明文件 gitlab-runner-pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: gitlab-runner-pvc              # 创建名称为gitlab-runner-pvc的pvc
  namespace: gitlab-runners
spec:
  accessModes:
  - ReadWriteMany                      # 访问模式
  storageClassName: rbd                # 存储类名称
  resources:
    requests:
      storage: 2Gi                     # 存储大小

➤ 创建 PVC

[root@master gitlab-runner]# kubectl apply -f gitlab-runner-pvc.yaml                                         
persistentvolumeclaim/gitlab-runner-pvc created
[root@master gitlab-runner]# kubectl get pvc -n gitlab-runners       
NAME                STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
gitlab-runner-pvc   Bound    pvc-a620cd43-f396-4626-8599-c973c19cddd3   2Gi        RWO            rbd            4s

查看已经在极狐GitLab Runner 名称空间下已经创建好了 PVC。

➤ 配置 Values

在上面,我们配置绑定宿主机 Docker 进程时,已经将 PVC 配置进去了,我们还需要在 Charts 的 values.yaml 下,新添加配置 Volume 信息,并在 values.yaml 配置相应变量。

# 添加在values.yaml 的最后即可
maven:
  cache:
    pvcName: gitlab-runner-pvc
    mountPath: /home/cache/maven

安装极狐GitLab Runner

配置文件比较长,可以根据需要自行配置,下面是本文示例需要配置的地方。

[root@master gitlab-runner]# egrep "^$|^#|^[[:space:]]+#" -v values.yaml 
imagePullPolicy: IfNotPresent
gitlabUrl: https://jihulab.com/                                                                                                # gitlab url
runnerRegistrationToken: "nnxxxxxxxxxxxxxxxS"                                        # gitlab token
unregisterRunners: true
terminationGracePeriodSeconds: 3600
concurrent: 10
checkInterval: 30
rbac:
  create: true
  clusterWideAccess: false
  serviceAccountName: gitlab                                                                                                        # rbac的sa
metrics:
  enabled: true
runners:
  image: ubuntu:16.04                                                                                                                                        # 使用的镜像
  tags: "gitlab-runner"
  privileged: true
  imagePullPolicy: "if-not-present"                                                                                # 如果执行具体job的runner不存在则拉取
  pollTimeout: 180
  outputLimit: 4096
  cache: {}
  builds: {}
  services: {}
  helpers: {}
  serviceAccountName: gitlab                                                                                                        # serviceaccount
  nodeSelector: {}

securityContext:
  fsGroup: 65533
  runAsUser: 100
resources: {}
affinity: {}
nodeSelector: {}
tolerations: []
hostAliases: []
podAnnotations: {}
podLabels: {}
maven:                                                                                                                                                                                                # 配置maven缓存信息
  cache:
    pvcName: gitlab-runner-pvc                                                                                                # pvc信息
    mountPath: /home/cache/maven                                                                                        # 挂载点

➤ 安装极狐GitLab Runner

在配置完成 values.yaml 相关字段后,我们利用 Helm 来进行安装。后期如果有变动,直接修改 value.yml ,进行更新即可 helm upgrade gitlab-rujner gitlab-runner/

[root@master gitlab-runner]# helm install --name gitlab-runner -f gitlab-runner/values.yaml --namespace gitlab-runners gitlab-runner/
NAME:   gitlab-runner
LAST DEPLOYED: Sun Feb 23 22:45:37 2020
NAMESPACE: gitlab-runners
STATUS: DEPLOYED

RESOURCES:
==> v1/ConfigMap
NAME                         DATA  AGE
gitlab-runner-gitlab-runner  5     1s

==> v1/Deployment
NAME                         READY  UP-TO-DATE  AVAILABLE  AGE
gitlab-runner-gitlab-runner  0/1    1           0          1s

==> v1/Pod(related)
NAME                                          READY  STATUS   RESTARTS  AGE
gitlab-runner-gitlab-runner-6745dd4cd6-r9z28  0/1    Pending  0         0s

==> v1/Secret
NAME                         TYPE    DATA  AGE
gitlab-runner-gitlab-runner  Opaque  2     1s

查看已经成功运行的相关 Pod 资源,极狐GitLab Runner的配置是通过 Configmap 挂载进去,如有新的配置可以修改,并删除之前的极狐GitLab Runner 的 Pod,其 Deployment 控制器会为 Pod 挂载新的配置文件。

➤ 查看 Pod 运行状态

[root@master ~]# kubectl get po -n gitlab-runners 
NAME                                           READY   STATUS    RESTARTS   AGE
gitlab-runner-gitlab-runner-6745dd4cd6-r9z28   1/1     Running   0          21h

➤ 查看 Configmap 及 Pod 中挂载的配置

此时,可以进入 Pod 查看 Runner 的配置文件(/home/gitlab-runner/.gitlab-runner/config.toml)。这个文件就是根据之前配置的 values.yaml 自动生成的。

[root@master ~]# kubectl get cm -n gitlab-runners  gitlab-runner-gitlab-runner 
NAME                          DATA   AGE
gitlab-runner-gitlab-runner   5      21h

➤ 登录极狐GitLab 控制台查看目前极狐GitLab Runner 已经注册上了

➤ 当 Pod 运行起来后,查看完整配置

[root@master gitlab-runner]# kubectl exec -it -n gitlab-runners gitlab-runner-gitlab-runner-6c7dfd859c-62dv5 -- cat /home/gitlab-runner/.gitlab-runner/config.toml
listen_address = "[::]:9252"
concurrent = 10
check_interval = 30
log_level = "info"

[session_server]
  session_timeout = 1800

[[runners]]
  name = "gitlab-runner-gitlab-runner-6c7dfd859c-62dv5"
  output_limit = 4096
  request_concurrency = 1
  url = "https://jihulab.com/"         # 注册的url
  token = "eRxxxxxb63q"         # gitlab注册的token
  executor = "kubernetes"             # executor为kubernetes
  [runners.custom_build_dir]
  [runners.cache]
    [runners.cache.s3]
    [runners.cache.gcs]
  [runners.kubernetes]
    host = ""
    bearer_token_overwrite_allowed = false
    image = "ubuntu:16.04"            # 使用的镜像为ubuntu
    namespace = "gitlab-runners"         # 使用的namespace为gitlab-runners
    namespace_overwrite_allowed = ""
    privileged = true
    poll_timeout = 180
    service_account = "gitlab"          # serviceaccont 为gitlab
    service_account_overwrite_allowed = ""
    pod_annotations_overwrite_allowed = ""
    [runners.kubernetes.pod_security_context]
    [runners.kubernetes.volumes]
  [[runners.kubernetes.volumes.pvc]]
    name = "gitlab-runner-pvc"          # 挂载的pvc名称
    mount_path = "/home/cache/maven"       # 挂载在pod下的缓存目录
  [[runners.kubernetes.volumes.host_path]]
    name = "docker"
    mount_path = "/var/run/docker.sock"      # 绑定宿主机的docker.sock

至此,我们已经将极狐GitLab Runner 在 K8s 集群中运行起来。

接下来,让我们来集成 CI。

集成 CI

定义文件

由于使用的 Executor 不同,所以. gitlab-ci.yml 和之前服务器也有些不同,不如 Image,默认如果每个Stage 中没有指定某个 Image,则使用该 Image。

image: docker:latest
variables:
  DOCKER_DRIVER: overlay2
  # k8s 挂载本地卷作为 maven 的缓存
  MAVEN_OPTS: "-Dmaven.repo.local=/home/cache/maven"

stages:
  - package       # 源码打包阶段
  - docker_build        # 镜像构建和打包推送阶段
  - deploy_k8s     # 应用部署阶段
  
before_script:
  - export APP_TAG="${CI_COMMIT_TAG:-${CI_COMMIT_SHA::8}}"    # 定义制作好的镜像tag

maven-package:
  #image: maven:3.5-jdk-8-alpine
  image: registry.cn-beijing.aliyuncs.com/codepipeline/public-blueocean-codepipeline-slave-java:0.1-63b99a20  # maven镜像进行java源码的build
  tags:
    - gitlab-runner    # 指定使用gitlab-runner来追寻
  stage: package
  script:
    - mvn clean package -Dmaven.test.skip=true
  artifacts:       # 将生成的war包上传到pvc挂载目录中
    paths:
      - target/*.war
docker-build:
  tags:
    - gitlab-runner
  stage: build
  script:
    - echo "Building Dockerfile-based application..."
    - docker build -t ${REGISTRY}/${QHUB_NAMESPACE}/${APP_NAME}:${APP_TAG} .     # 构建镜像
    - docker login --username=${DOCKER_USERNAME} ${REGISTRY} -p ${DOCKER_PASSWORD}  # 登录镜像仓
    - docker push ${REGISTRY}/${QHUB_NAMESPACE}/${APP_NAME}:${APP_TAG}        # push镜像
  only:
    - master
k8s-deploy:
  image: bitnami/kubectl:latest    # 使用kubectl镜像来进行最终的部署
  tags:
    - gitlab-runner
  stage: deploy
  script:
    - echo "deploy to k8s cluster..."
    - sed -i "s@$(grep -E "^[[:space:]]+image:" deployment.yaml | awk '{print $2}' |head -1)@${REGISTRY}/${QHUB_NAMESPACE}/${APP_NAME}:${APP_TAG}@g"  deployment.yaml   # 替换deployment中的镜像
    - kubectl apply -f deployment.yaml      # 应用资源清单文件
  only:
    - master

可以看到 CI 文件中,我们定义了三个 Stage:

  • 利用 Maven 镜像进行打包,生成 war 包制品到缓存目录中;

  • 利用 Docker 镜像,根据项目中的 Dockerfile 对缓存中的制品进行镜像构建,构建完成后,登录镜像仓库进行镜像推送;

  • 利用 Kubectl 镜像先对原有 Deployment 文件进行镜像替换,之后将资源清单更新至 K8s 集群中;

  • 在为镜像打 Tag 时,可以自行设置,也可以利用 Commit 来对照 Git 版本。

注意事项

  • 由于在镜像构建的 Stage 中,需要使用 Docker 命令进行相关操作,因此需要绑定本地 Docker 守护进程;

  • Maven 仓库缓存,在需要生产制品并保存的构建中,需要外部存储来存放制品;

  • 在 Stage 中引用的镜像最好能事先 Pull 到各个Node 节点上,不然第一次运行 CI,如果网络有波动或带宽小,可能会因为镜像下载超时导致 CI 失败。

配置变量

由于在 CI 文件中有一些敏感信息,例如镜像仓库的登录信息、后期可以更改的镜像名称等,可利用环境注入方式,使得 CI 文件脱敏而且更具灵活性和适用性

添加极狐GitLab Runner 可用的环境变量,本示例添加变量如下:

  • APP_NAME:制作完成后镜像的名称;

  • DOCKER_USERNAME:镜像仓库用户名;

  • DOCKER_PASSWORD 镜像仓库密码;

  • QHUB_NAMESPACE:镜像仓库名称空间。在该项目中,我们使用腾讯云的镜像仓库,当然可以自建 Harbor 或使用其他公有云提供的镜像仓库或者 Dockerhub 等;

  • REGISTRY:镜像仓库的地址。

运行测试

在配置好了 CI 文件后,让我们来运行测试,提交代码,或者手动运行。

运行 Pipeline

在项目 CI/CD 右上角有运行流水线按钮。

在图中,我们可以看到可以并行运行多个 Pipeline,互不影响。

查看运行 Pod

登录 K8s 集群,查看此时运行的 Pod:

查看 Job

➤ 打包镜像

➤ 镜像构建

➤ 部署进 K8s

查看构建情况

➤ 查看 Pipeline

➤ 查看构建应用

至此我们就完成了极狐GitLab CI + K8s 示例。让我们尽情享受 K8s +极狐GitLab CI 为我们带来畅快淋漓的发布体验吧。

注意事项


  • 实战中的资源清单文件只写了 Deployment,读者可以根据自己项目调整,可以将 Service/Configmap/HPA 等资源清单文件也放在项目中托管,当然也可以制作成 Helm 应用,每次发布利用 Helm 来更新应用;

  • 在极狐GitLab CI 中,注意将敏感信息例如镜像仓库的登录方式等进行脱敏,将有变化的字段设置为变量,使得 CI 更扩展性及灵活性;

  • 在此节中,部分内容需要读者具备一定的 K8s 经验,例如其中的 Helm 及相关的资源清单文件,如事先了解业务微服务后,看本章节内容更为合适;

  • 注意在写 RBAC 与 PVC 资源清单的名称空间为你想部署的业务名称空间,即例如你想把资源清单部署在 Common 名称空间下,就需要把 PVC 和 RBAC 创建在 Common 名称空间下,将 极狐GitLab Runner 注册在Common名称空间下。

总结思考


通过本文极狐GitLab CI 实战总结,笔者再次安利大家去了解极狐GitLab 的此项特性。如果您的公司困于多套系统维护的复杂性,不妨尝试下极狐GitLab CI 简单集成

在云原生时代,将工具或中间件下沉到基础设施中,用户只需要专注于自身业务开发,在敏捷高效的文化中协作、快速试错、快速反馈、持续改进、不断迭代,以 Git 为契机打破研发与运维的壁垒隔阂,实现产品更快、更频繁、更稳定的交付。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/571805.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python实战基础11-函数

1 函数的创建于调用 1.1 创建一个函数 创建函数也称为定义函数&#xff0c;定义函数的格式如下&#xff1a; def functionname([parameterlist]): [comments] [functionbody] 参数说明&#xff1a; functionname&#xff1a;函数名称&#xff0c;在调用函数时使用。 paramete…

用echarts绘制的柱状图、折柱结合图,源码文末免费拿!

文章目录 Apache EchartsNPM 安装 ECharts在线定制 ECharts使用 Echarts 绘制基础柱状图绘制带背景的柱状图绘制带背景的柱状图绘制多条柱状图绘制条形柱状图绘制带标记的柱状图绘制折线图和柱状图绘制多轴折线图和柱状图源码地址 Apache Echarts 本文中的所有代码&#xff0c…

剑指offer(C++)-JZ46:把数字翻译成字符串(算法-动态规划)

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 题目描述&#xff1a; 有一种将字母编码成数字的方式&#xff1a;a->1, b->2, ... , z->26。 现在给一串数字&#xf…

如何在Angular应用程序中插入自定义 CSS?这里有答案!

Kendo UI for Angular是专用于Angular开发的专业级Angular组件&#xff0c;telerik致力于提供纯粹的高性能Angular UI组件&#xff0c;无需任何jQuery依赖关系。 Kendo UI R1 2023正式版下载(Q技术交流&#xff1a;726377843&#xff09; 为什么需要在 Angular 应用程序中插入…

兼容性测试点和注意项,建议收藏

一&#xff1a;兼容性测试的概念&#xff1a;就是验证开发出来的程序在特定的运行环境中与特定的软件、硬件或数据相组合是否能正常运行、有无异常的测试过程。 二&#xff1a;兼容性测试的分类&#xff1a; &#xff08;1&#xff09;浏览器兼容性测试 指的是在浏览器上检查…

航空公司预订票数学建模论文

航空公司预订票数学建模论文篇1 试谈机票订票模型与求解 一、概述 1. 问题背景描述 在激烈的市场竞争中&#xff0c;航空公司为争取更多的客源而开展的一个优质服务项目是预订票业务,本模型针对预订票业务&#xff0c;建立二元规划订票方案&#xff0c;既考虑航空公司的利润最大…

form-create和form-create-designer创建自定义组件

在项目中&#xff0c;我需要使用表单设计器form-create-designer设计带有选择用户的弹窗组件&#xff0c;而设计器内置的组件不能满足需求&#xff0c;因此要创建自定义组件。form-create 支持在表单内部生成任何 vue 组件。 1.开发选择用户的组件 SelectUser.vue <!--用户…

论文《Diagnostic accuracy of CT imaging parameters in pelvic lipomatosis》案例分析

一、引言 在该篇文章的引言部分&#xff0c;作者明确阐述了本篇论文的研究目的、问题和方法&#xff0c;并指出了研究的贡献和创新点。以下是具体内容&#xff1a; 研究目的&#xff1a;本研究的目的是评估盆腔脂肪肥大的CT成像特征&#xff0c;并探讨其在诊断和管理中的应用…

Java程序设计入门教程--包

情形 在Java中&#xff0c;包(package)是一种松散的类的集合&#xff0c;它可以将各种类文件组织在一起&#xff0c;就像磁盘的目录&#xff08;文件夹&#xff09;一样。包的管理机制提供了类的多层次命名空间避免了命名冲突问题&#xff0c;解决了类文件的组织问题&#xff0…

Midjourney AI绘画中文教程(完整版)

我有一种预感&#xff0c;这篇内容一定会破万~~~ Midjourney AI绘画中文教程&#xff0c;Midjourney是一款2022年3月面世的AI绘画工具&#xff0c;创始人是David Holz。 只要输入想到的文字&#xff0c;就能通过人工智能产出相对应的图片&#xff0c;耗时只有大约一分钟&…

Linux Shell 实现部署单机Oracle 21C

oracle前言 Oracle开发的关系数据库产品因性能卓越而闻名&#xff0c;Oracle数据库产品为财富排行榜上的前1000家公司所采用&#xff0c;许多大型网站也选用了Oracle系统&#xff0c;是世界最好的数据库产品。此外&#xff0c;Oracle公司还开发其他应用程序和软件。同时&#…

《Spring Guides系列学习》guide1 - guide5

要想全面快速学习Spring的内容&#xff0c;最好的方法肯定是先去Spring官网去查阅文档&#xff0c;在Spring官网中找到了适合新手了解的官网Guides&#xff0c;一共68篇&#xff0c;打算全部过一遍&#xff0c;能尽量全面的了解Spring框架的每个特性和功能。 开始吧&#xff0…

UDP就一定比TCP快吗?

前言 话说&#xff0c;UDP比TCP快吗&#xff1f; 相信就算不是八股文老手&#xff0c;也会下意识的脱口而出&#xff1a;”是“。 但这也让人好奇&#xff0c;用UDP就一定比用TCP快吗&#xff1f;什么情况下用UDP会比用TCP慢&#xff1f; 我们今天就来聊下这个话题。 使用…

关于使用--- pyinstaller---无法打包py文件为exe的问题集合

目录 安装 pyinstaller 问题1&#xff1a; 解决办法&#xff1a; CMD中输入 问题2&#xff1a; 解决办法&#xff1a; CMD中输入 问题3&#xff1a; 将py文件打包成exe中&#xff0c;需要按照如下在CMD中输入 PyInstaller介绍 PyInstaller是一个Python库&#xff0c;可以…

智慧档案馆八防是怎么建设的?都需要注意哪些内容

智慧档案馆八防环境监控系统一体化解决系统方案 智慧档案库房一体化平台通过智慧档案管理&#xff0c;实现智慧档案感知协同处置功能&#xff1b;实现对档案实体的智能化识别、定位、跟踪监控&#xff1b;实现对档案至智能密集架、空气恒湿净化一体设备、安防设备&#xff0c…

基于java用队列实现栈

基于java用队列实现栈 问题描述 请你仅使用两个队列实现一个后入先出&#xff08;LIFO&#xff09;的栈&#xff0c;并支持普通栈的全部四种操作&#xff08;push、top、pop 和 empty&#xff09;。 实现 MyStack 类&#xff1a; void push(int x) 将元素 x 压入栈顶。 int …

C++第六章:函数

函数 一、函数基础1.0 简介形参和实参形参列表函数的返回类型 1.1 局部对象自动对象局部静态对象 1.2 函数声明在头文件中进行函数声明 1.3 分离式编译编译和链接多个源文件 二、参数传递2.1 传值参数指针形参 2.2 传引用参数使用形参返回额外信息 2.3 const形参和实参指针或引…

「实在RPA·人社数字员工」促进人力社保数字办公战略转型

一、人力社保部门数字化转型的重要性 伴随着国家放宽人力资源市场准入条例&#xff0c;多次出台相关扶持政策&#xff0c;市场竞争加剧&#xff0c;后疫情时代格局的大变局&#xff0c;如何提高服务质量和效率&#xff0c;如何降本增效&#xff0c;成为人力资源和社会保障行业…

【算法】不使用LinkedHashMap实现一个LRU缓存

文章目录 什么是LRU&#xff1f;设计思路代码实现 LRU是我在面试过程中遇到的比较多的算法题了&#xff0c;并且我自己的项目中也手写了LRU算法&#xff0c;所以觉得还是有必要掌握一下这个重要的算法的。 什么是LRU&#xff1f; LRU是一种缓存淘汰策略。 我们知道&#xff0…

经典文献阅读之--PIBT(基于可见树的实时规划方案)

0. 简介 作为路径规划而言&#xff0c;不单单有单个机器人自主路径规划&#xff0c;近年来随着机器人行业的兴起&#xff0c;多机器人自主路径规划也越来越受到关注&#xff0c;对于多智能体寻路(MAPF)。一般的操作会给定一个地图、机器人集群、以及它们的初始位置和目的地&am…