基于Docker容器的,Jenkins、GitLab构建持续集成CI

** 开发者将代码提交(push)到GitLab后,GitLab通过Hook通知jenkins,jenkins自动从GitLab中获取项目最新的源码进行集成和发布。
基于Docker,创建一个私有GitLab的容器,创建一个jenkins的容器**

1. 构建私有的GitLab容器

https://about.gitlab.com/installation/#centos-7,直接安装gitlab,不借助docker

通过docker-compose的方式安装gitlab,docker-compose这个命令需要单独安装,docker-compose会对指定目录下的docker-compose.yml文件进行执行,这个文件会一次性启动所编辑的镜像,及所要用到的参数,官方提供的yml文件内容如下:

#Install docker-compose
 sudo curl -L https://github.com/docker/compose/releases/download/1.17.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-composeanzhu
sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version
>
```javascript
version: '2'

services:
  redis:
    restart: always
    image: sameersbn/redis:latest
    command:
    - --loglevel warning
    volumes:
    - /srv/docker/gitlab/redis:/var/lib/redis:Z   #文件的挂载点

  postgresql:
    restart: always
    image: sameersbn/postgresql:9.6-2
    volumes:
    - /srv/docker/gitlab/postgresql:/var/lib/postgresql:Z   #文件的挂载点
    environment:
    - DB_USER=gitlab
    - DB_PASS=password
    - DB_NAME=gitlabhq_production
    - DB_EXTENSION=pg_trgm

  gitlab:
    restart: always
    image: sameersbn/gitlab:9.1.4
    depends_on:
    - redis
    - postgresql
    ports:
    - "10080:80"
    - "10022:22"
    volumes:
    - /srv/docker/gitlab/gitlab:/home/git/data:Z  #文件的挂载点
    environment:
    - DEBUG=false

    - DB_ADAPTER=postgresql
    - DB_HOST=postgresql
    - DB_PORT=5432
    - DB_USER=gitlab
    - DB_PASS=password
    - DB_NAME=gitlabhq_production

    - REDIS_HOST=redis
    - REDIS_PORT=6379

    - TZ=Asia/Kolkata
    - GITLAB_TIMEZONE=Kolkata

    - GITLAB_HTTPS=false
    - SSL_SELF_SIGNED=false

    - GITLAB_HOST=localhost
    - GITLAB_PORT=10080
    - GITLAB_SSH_PORT=10022
    - GITLAB_RELATIVE_URL_ROOT=
    - GITLAB_SECRETS_DB_KEY_BASE=long-and-random-alphanumeric-string
    - GITLAB_SECRETS_SECRET_KEY_BASE=long-and-random-alphanumeric-string
    - GITLAB_SECRETS_OTP_KEY_BASE=long-and-random-alphanumeric-string

    - GITLAB_ROOT_PASSWORD=
    - GITLAB_ROOT_EMAIL=

    - GITLAB_NOTIFY_ON_BROKEN_BUILDS=true
    - GITLAB_NOTIFY_PUSHER=false

    - GITLAB_EMAIL=notifications@example.com
    - GITLAB_EMAIL_REPLY_TO=noreply@example.com
    - GITLAB_INCOMING_EMAIL_ADDRESS=reply@example.com

    - GITLAB_BACKUP_SCHEDULE=daily
    - GITLAB_BACKUP_TIME=01:00

    - SMTP_ENABLED=false
    - SMTP_DOMAIN=www.example.com
    - SMTP_HOST=smtp.gmail.com
    - SMTP_PORT=587
    - SMTP_USER=mailer@example.com
    - SMTP_PASS=password
    - SMTP_STARTTLS=true
    - SMTP_AUTHENTICATION=login

    - IMAP_ENABLED=false
    - IMAP_HOST=imap.gmail.com
    - IMAP_PORT=993
    - IMAP_USER=mailer@example.com
    - IMAP_PASS=password
    - IMAP_SSL=true
    - IMAP_STARTTLS=false

    - OAUTH_ENABLED=false
    - OAUTH_AUTO_SIGN_IN_WITH_PROVIDER=
    - OAUTH_ALLOW_SSO=
    - OAUTH_BLOCK_AUTO_CREATED_USERS=true
    - OAUTH_AUTO_LINK_LDAP_USER=false
    - OAUTH_AUTO_LINK_SAML_USER=false
    - OAUTH_EXTERNAL_PROVIDERS=

    - OAUTH_CAS3_LABEL=cas3
    - OAUTH_CAS3_SERVER=
    - OAUTH_CAS3_DISABLE_SSL_VERIFICATION=false
    - OAUTH_CAS3_LOGIN_URL=/cas/login
    - OAUTH_CAS3_VALIDATE_URL=/cas/p3/serviceValidate
    - OAUTH_CAS3_LOGOUT_URL=/cas/logout

    - OAUTH_GOOGLE_API_KEY=
    - OAUTH_GOOGLE_APP_SECRET=
    - OAUTH_GOOGLE_RESTRICT_DOMAIN=

    - OAUTH_FACEBOOK_API_KEY=
    - OAUTH_FACEBOOK_APP_SECRET=

    - OAUTH_TWITTER_API_KEY=
    - OAUTH_TWITTER_APP_SECRET=

    - OAUTH_GITHUB_API_KEY=
    - OAUTH_GITHUB_APP_SECRET=
    - OAUTH_GITHUB_URL=
    - OAUTH_GITHUB_VERIFY_SSL=

    - OAUTH_GITLAB_API_KEY=
    - OAUTH_GITLAB_APP_SECRET=

    - OAUTH_BITBUCKET_API_KEY=
    - OAUTH_BITBUCKET_APP_SECRET=

    - OAUTH_SAML_ASSERTION_CONSUMER_SERVICE_URL=
    - OAUTH_SAML_IDP_CERT_FINGERPRINT=
    - OAUTH_SAML_IDP_SSO_TARGET_URL=
    - OAUTH_SAML_ISSUER=
    - OAUTH_SAML_LABEL="Our SAML Provider"
    - OAUTH_SAML_NAME_IDENTIFIER_FORMAT=urn:oasis:names:tc:SAML:2.0:nameid-format:transient
    - OAUTH_SAML_GROUPS_ATTRIBUTE=
    - OAUTH_SAML_EXTERNAL_GROUPS=
    - OAUTH_SAML_ATTRIBUTE_STATEMENTS_EMAIL=
    - OAUTH_SAML_ATTRIBUTE_STATEMENTS_NAME=
    - OAUTH_SAML_ATTRIBUTE_STATEMENTS_FIRST_NAME=
    - OAUTH_SAML_ATTRIBUTE_STATEMENTS_LAST_NAME=

    - OAUTH_CROWD_SERVER_URL=
    - OAUTH_CROWD_APP_NAME=
    - OAUTH_CROWD_APP_PASSWORD=

    - OAUTH_AUTH0_CLIENT_ID=
    - OAUTH_AUTH0_CLIENT_SECRET=
    - OAUTH_AUTH0_DOMAIN=

    - OAUTH_AZURE_API_KEY=
    - OAUTH_AZURE_API_SECRET=
    - OAUTH_AZURE_TENANT_ID=

在docker-compose.yml文件所在目录下,执行docker-compose up命令(docker-compose命令需要安装),如果之前没有下载过GitLab的镜像会自动下载,如果下载过就直接启动已有的容器。

这里会在docker创建一个新的网桥,gitlab所需要的gitlab容器和redis容器及postgresql容器都在这个网桥指定的网段内,可以通过docker network ls查看.

网桥的名称通常为你yml文件所在目录名称的小写加上下划线default,例如mygitlab_default。这个很有用,因为如果你想要容器内部互联,就需要指定所要连接的容器在一个网段内,例如jenkins容器如果想内部连接gitlab容器,就得都在mygitlab_default这个网桥提供的网段内,Docker默认会为容器指定在docker0这个网段内的一个ip,通常会是172.17.. 我的gitlab默认在172.18,所以需要在接下来创建jenkins容器并启动时,指定到18这个网段内,当然你想通过宿主机的ip和端口也是可以的

执行完成之后,gitlab容器的80端口绑定在了宿主机的10080端口,同时gitlab容器的22端口(ssh)绑定在宿主机10022端口。可以通过访问localhost:10080来访问私有仓库

2. 构建Jenkins容器

Jenkins容器安装Jenkins的rpm包,Jenkins依赖 JDK,所以需要在Jenkins的容器中安装配置jdk,本人使用jdk1.8,同时需要Jenkins的容器调用maven的打包命令,所以也需要配置安装maven,本人使用maven 3.3.9。

a.通过Dockerfile构建一个jenkins容器,基于centos7的镜像。

这里不推荐将一个基础镜像一次性打包成完整的应用镜像,建议构建三层镜像模型。
所谓三层镜像就是,基础镜像,中间件镜像,应用镜像。例如我要构建一个Jenkins 的镜像,打包一个基于Centos7 和一些常用工具的镜像就是基础镜像,例如叫Centos7-base。然后这里Jenkins依赖Java和Maven,所以在基于Centos7-base的基础上安装配置java及maven后,再打包的镜像为中间件镜像,例如叫Centos7-jdk8-mvn3,这层中间件的镜像我们为来的复用会很高,以后只要有基于java1.8和maven3的,就可以直接使用这个镜像进行构建。最后我们再在Centos7-jdk8-mvn3的基础上安装配置jenkins,最后打包运用在生产环境。

b.构建基础镜像,整合jdk及mvn。配置PATH ,安装所需要的工具,Dockerfile如下:

#base on centos 7 image

FROM daocloud.io/centos:7
MAINTAINER hoewon
LABEL JDK \ 1.8

COPY jdk1.8 /usr/local/jdk1.8/  \
             maven /usr/local/maven/

RUN yum install -y openssh-server openssh-clients git 

RUN yum install -y iproute  net-tools

ENV JAVA_HOME /usr/local/jdk1.8

ENV PATH $JAVA_HOME/bin:$PATH

EXPOSE 8080

ENTRYPOINT /bin/bash
将要复制进镜像里的jdk和maven文件放到与Dockerfile相同的目录下

执行命令打包镜像

#最后 . 是当前目录的意思,不可省略,或自定义Dockerfile所在目录

docker build -t repo/name:tag  .  

#成功后查看本地镜像

docker images

c.通过基础镜像安装jenkins,也是通过Dockerfile

#A jenkins 2.7.4 on centos 7 image
#基于刚才做好的基础镜像
FROM 127.0.0.1:5000/env/centos7-jdk8-mvn:1.3
MAINTAINER hoewon
LABEL JDK1.8 \ Jenkins-2.7.4
#复制jenkins rpm至镜像
COPY jenkins.rpm /usr/local/

#创建jenkins用户,并更改密码

RUN useradd jenkins && echo "jenkins password"  > passwd jenkins --stdin

#安装jenkins

RUN rpm -ivh /usr/local/jenkins.rpm

#更改jenkins安装文件的所有者

RUN rpm -ql jenkins | xargs chown -R jenkins:jenkins

#创建jenkins日志文件

RUN touch /usr/lib/jenkins/jenkins-logs 

#更改日志文件所有者

RUN chown jenkins:jenkins /usr/lib/jenkins/jenkins-logs

#曝光8080端口

EXPOSE 8080

#启动容器时使用jenkins用户

USER jenkins

#定义用户空间为工作空间

WORKDIR /home/jenkins

#启动容器时启动jenkins

ENTRYPOINT java -jar /usr/lib/jenkins/jenkins.war &> /usr/lib/jenkins/jenkins-logs

d.运行jenkins容器,这里需要将container的网络设置跟GtiLab同网络的环境下,同时我们希望jenkins容器在用maven打包之后,在调用docker惊醒封装镜像,然后推送镜像至私有的镜像仓库,所以我们把宿主机的/usr/bin/docker 和/run/docker.sock 和所依赖的共享库文件,在启动容器时一并挂载至容器内部。

# --net 指定docker的网桥
 docker run -idt   --net mygitlab_default --name jenkins_c -p 8888:8080 -v /usr/lib64/libltdl.so.7:/usr/lib64/libltdl.so.7  -v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker 127.0.0.1:5000/myjenkins:1.0 /bin/bash

e.容器启动后,8080端口被绑定到了宿主机的8888端口,访问localhost:8888来访问jenkins
首次登录jenkins会需要输入jenkins的超级管理员密码,这个密码在jenkins第一次启动的日志中,可以进入jenkins容器,查看运行日志,也可以根据页面提示,直接去jenkins的家目录下一个.jenkins/secrets/init…..的文件内查看密码。登录后注册一个用户,并在系统管理-管理插件下,安装GitLab的插件。第一次运行jenkins会让你选择安装插件,选择第一个推荐的安装后,在管理插件的可选插件tab下搜索Gitlab Plugin 和Gitlab Hook Plugin插件进行安装,然后重启jenkins

3.构建私有的Docker 镜像仓库
拉取一个docker 的镜像仓库镜像,并运行该容器,容器运行后会绑定宿主机5000端口,我个人用的是daocloud.io提供的镜像,这个镜像仓库需要注册。

docker run \
         -e SETTINGS_FLAVOR=s3 \
         -e AWS_BUCKET=acme-docker \
         -e STORAGE_PATH=/registry \
         -e AWS_KEY=AKIAHSHB43HS3J92MXZ \
         -e AWS_SECRET=xdDowwlK7TJajV1Y7EoOZrmuPEJlHYcNP2k4j49T \
         -e SEARCH_BACKEND=sqlalchemy \
         -p 5000:5000 \
         daocloud.io/registry

运行成功后,可以访问http://localhost:5000/v2/_catalog 来查看本地仓库信息

4.构建持续集成环境
万事具备,下面我们开始利用gitlab,jenkins,来构建持续集成环境。

a.在gitlab中创建一个项目,项目类为public,创建后会有如下提示,这些提示用来告诉你如何通过客户端下载项目,并提交项目

#Command line instructions
#Git global setup
git config --global user.name "jenkins"
git config --global user.email "15561581025@163.com"
#Create a new repository
git clone ssh://git@localhost:10022/jenkins/demo.git
cd demo
touch README.md
git add README.md
git commit -m "add README"
git push -u origin master
#Existing folder
cd existing_folder
git init
git remote add origin ssh://git@localhost:10022/jenkins/demo.git
git add .
git commit
git push -u origin master
#Existing Git repository
cd existing_repo
git remote add origin ssh://git@localhost:10022/jenkins/demo.git
git push -u origin --all
git push -u origin --tags

b.进入jenkins容器,然后通过git客户端,拉取项目。在拉取之前,需要用使用ssh-keygen来生成当前jenkins用户在jenkins容器的公钥密钥,ssh-keygen需要安装openssh。

ssh-keygen – t rsa

可以一路回车,默认生成在jenkins用户的家目录下的一个.ssh的文件夹,将.ssh/id_rsa.pub的内容全部复制

c.登录gitlab,右上角下拉列表下选择setting,然后在主页面有一个SSH Keys的tab页,将你刚才复制的公钥内容添加至Key这个文本框,然后点击Add key。这个步骤的意思是,如果你想让jenkins通过ssh协议从gitlab拉取项目,需要认证,配置的公钥就是允许jenkins容器的jenkins用户所运行的jenkins从gitlab通过ssh协议拉取项目(有点别扭,但是需要注意的是jenkins这个容器主机和jenkins用户,jenkins程序是jenkins用户启动的)。
(这里有一个没有解决的问题,就是关于拉取private类型的项目,需要做的ssh认证,需要公钥密钥匹配,但是没有实现,所以暂时项目都是public。如果public的项目的话,可以通过http协议进行拉取,但是需不需要配置ssh的公钥,我也没试过,因该是不需要把。)

在配置好key之后,我们回到jenkins容器,当前用户为jenkins。我们想通过git客户端拉取项目的第二个准备工作,需要配置git的全局配置。

git  config --global   user.name=”yourName”

我的gitlab 和jenkins的用户都是jenkins,这里应该填写的是git用户名

git config –global user.email=”your email”

这两个配置完成后,我们可以就可以拉取项目到本地了,以我自己demo为例

git clone ssh://git@localhost:10022/jenkins/eurka.git

d.现在拉取到当前目录的eurka是个空项目,我们把我们要上传的项目源码和Dockerfile(用来jenkins调用docker打包镜像用的)添加至这个目录,然后git add ,git commit ,git push 命令将本地文件添加提交并推送整合至gitlab这个项目的某个分支下,默认是master

e.提交完成后,我们开始配置jenkins,以jenkins用户登录jenkins,新建,选择 --构建一个自由风格的软件项目然后确定

f.然后进入到这个项目的配置下,在源码管理选择Git,然后在Repository URL下,填入项目的ssh地址,注意这里不可一世用localhost,你可以填写主机的ip加上10022端口,也可以配置gitlab容器的ip地址加上22端口,我这里配置的是我的容器地址,例如ssh://git@172.18.0.4:22/jenkins/eurka.git,这里不要写10022端口!!!!因为是public项目,所以不需要添加认证
g.在构建触发器下,选择Build wher a chage is pushed to GitLab……….将后面的地址复制,然后在gitlab这个项目的Setting下的Integrations下,勾选Push Event,找到Add webhook,并填写刚才复制的路径,我这里写的依然是容器ip,http://172.18.0.5:8080/project/eurka,没有使用localhost:8888这个url,保存

h.回到jenkins的设置,在构建中下Execute shell下,编写shell脚本,这里就是gitlab被push后,通过webhook的方式让jenkins自动从gitlab下拉取项目之后,要执行的代码
默认拉取之后,会在这个项目的路径下,如果不确定自己当前的工作目录,可以通过echo $WORKDIR来查看当前位置,例如我的项目叫eurka,这个项目下我上传了一个maven项目,所以我如果想要对这个maven项目打包,我得进入这个项目目录,然后对这个项目下的pom文件进行操作,贴出我的shell:

#先打印当前位置
pwd
#进入到我的maven项目
cd spring-cloud-02-service
#maven打包
mvn clean compile package -Dmaven.test.skip=true
#回到上一级,因为上一级有Dockerfile文件
cd ../
#这里我先移除掉了我之前的镜像,然后再重新构建一个镜像,如果当前有#这个镜像运行的容器,需要先停止容器,移除容器,最后移除镜像
docker rmi 127.0.0.1:5000/auto/eurka:1.0 . || docker build -t 127.0.0.1:5000/auto/eurka:1.0 .
#将打包的镜像推送到本地的docker仓库
docker push 127.0.0.1:5000/auto/eurka:1.0
#查看本地是否打包成功
docker images
#最后可以执行docker run -itd –name container_name -p xxxx:xxxx  repo/im#g:tag /bin/bash让jenkins调用宿主机的docker,运行刚才打包好的镜像,不#出意外,应该在我们指定的端口上可以访问这个项目了。

最初我们在run jenkins容器的时候,将宿主机的docker文件挂载进了容器内部,这个操作很重要,但我也很迷糊,但可以肯定的是,jenkins容器所运行的docker及操作是针对宿主机的docker的

后续的持续集成,要基于kubernetes,kubernetes会自动的找其节点自动拉取刚push的镜像,并自动部署。未完待续

时间: 2024-11-08 21:23:37

基于Docker容器的,Jenkins、GitLab构建持续集成CI的相关文章

使用Docker容器搭建Jenkins集群

本文讲的是使用Docker容器搭建Jenkins集群[编者的话]本文使用Jelastic Cloud搭建了Jenkins作业环境,包括手动部署和自动部署两个方式,对Jelastic Cloud感兴趣的用户,可以尝试注册一个免费账户,进行试验. 如果不太了解Jenkins,可以先了解如何"手动设置Jenkins"一节. 如果想自动部署,可以去了解 "自动化"一节. Jenkins,由于其管理大量节点,以及执行器(executor)对大量创建和部署提供响应的能力成为很热

基于 Jenkins 快速搭建持续集成环境

持续集成是一种软件开发实践,对于提高软件开发效率并保障软件开发质量提供了理论基础.Jenkins 是一个开源软件项目,旨在提供一个开放易用的软件平台,使持续集成变成可能.本文正是从持续集成的基本概念入手,通过具体实例,介绍了如何基于 Jenkins 快速搭建持续集成环境. 持续集成概述 什么是持续集成 随着软件开发复杂度的不断提高,团队开发成员间如何更好地协同工作以确保软件开发的质量已经慢慢成为开发过程中不可回避的问题.尤其是近些年来,敏捷(Agile) 在软件工程领域越来越红火,如何能再不断变

jenkins + Git 搭建持续集成环境

持续集成通过自动化构建.自动化测试以及自动化部署加上较高的集成频率保证了开发系统中的问题能迅速被发现和修复,降低了集成失败的风险,使得系统在开发中始终保持在一个稳定健康的集成状态.jenkins是目前广泛应用的持续集成工具,本文记录我使用jenkins+Git配置持续集成环境的整个流程以及踩到的坑(jenkins过程的坑往往不是在第一次配置,而是在配置结束后更改某些配置项的时候踩到). 总体流程如下: tomcat8.0下载地址:http://tomcat.apache.org/ jenkins

使用Subversion、Hudson和Eclipse构建持续集成系统的过程

持续集成系统是指持续地编译.测试.检查和部署源代码的系统. Martin Fowler 对持续集成是这样定义的 : 持续集成是一种软件开发实践,团队开发成员经常集成它们的工作,通常每个成员每天可能会发生多次集成.每次集成都通过自动化的构建(包括编译.发布.自动化测试)来验证,从而尽快地发现集成错误.这个过程可以大大减少集成的问题,从而让团队能够更快的开发内聚的软件. 持续集成有以下几个特点和要求: 有统一的源代码库. 开发人员基于同一个源代码库进行开发是进行持续集成的一个前提.为了让持续集成系统

ASP.NET 下如何构建持续集成环境

问题描述 请问有谁知道比较完整的ASP.NET下如何构建持续集成环境?最好是开源解决方案.能列出使用哪些工具,如何构建,如何做自动编译,自动单元测试,自动化构建,自动化发布和部署,自动化集成测试,以及包括版本控制等. 解决方案 解决方案二:这么多自动化那还要人干什么解决方案三:天啊,微软跟.net有关的才几个产品?tfs能实现这些全部功能.不过看你们公司研发体系应该达不到这种程度.解决方案四:做这些自动化是有原因的,虽然有这么多自动化,但也并不是就不需要人了解决方案五:引用2楼winner205

品高公开课 | 基于Docker容器的微服务架构实践

小编的话 "品高公开课"系列文章意在分享技术牛人的知识干货,每期主题都不一样哟!期待各位读者在文后发表留言,来一场技术上的交流和思想上的碰撞! 微服务以一种全新的架构设计模式,牵动了互联网应用从设计到运维整个流程方法论的变革. 而以Docker为代表的容器技术则为微服务理念提供了匹配的实现机制.本周五,将由品高软件工程师陈洪杰带讲述微服务架构的故事. 分享嘉宾 陈洪杰,目前就任品高广州云架构产品部--BingoCloud平台的软件开发工程师,拥有Docker,LXC等多个容器平台的项目

持续集成(CI)工具------Hudson/Jenkins(Continuous Integration)安装与配置详解

本文允许转载,但请标明出处:http://blog.csdn.net/wanghantong/article/40985653/, 版权所有 文章概述: 一. 描述了持续集成工具Hudson的安装与配置 二. 描述了Git .Maven环境的安装与配置 三. 描述了扩展邮件通知及其配置方法 四. 描述了jira的配置 一.Hudson简介 Hudson是Jenkins的前身,是基于Java开发的一种持续集成工具,用于监控持续的软件版本发布/测试项目 下载地址:http://eclipse.org

使用 Subversion、Hudson 和 Eclipse 构建持续集成系统

持续集成系统简介 持续集成系统是指持续地编译.测试.检查和部署源代码的系统. Martin Fowler 对 持续集成是这样定义的 : 持续集成是一种软件开发实践,团队开发成员经常集成它们的工作,通常每个成员每天可 能会发生多次集成.每次集成都通过自动化的构建(包括编译.发布.自动化测试)来验证,从而尽快地发现集成错误.这 个过程可以大大减少集成的问题,从而让团队能够更快的开发内聚的软件. 持续集成有以下几个特点和要求: 有统一的源代码库. 开发人员基于同一个源代码库进行开发是进行持续集成的一个

使用 svn+maven+jenkins(hudson)+Publish Over SSH plugins 构建持续集成及自动远程发布体系(转)

 1.安装jenkins     2.浏览器访问jenkins主页 http://192.168.0.1:8080/,点击"系统管理"     3.在插件管理中,安装Publish Over SSH插件     4.在系统设置中设置JDK,Maven,Subversion,邮件通知,Publish over SSH        JDK->填写JAVA_HOME:/usr/java/jdk1.6.0_26        Maven->选择自动安装(或设置环境变量);服务端通