wisetc / practice

Practice conclusion
5 stars 0 forks source link

gitlab 持续集成 gitlab-ci #5

Open wisetc opened 6 years ago

wisetc commented 6 years ago

react加gitlab-ci

使用create-react-app架构的项目每次发布都需要build,如果更新频繁,则未免过程枯燥又容易误操作。比如测试环境和生产环境切换通常要求更改接口等相关配置文件,容易遗漏,要是可以自动化发布,便可以分别在测试分支和生产分支放的相应的接口配置,不用改来改去。另一个显而易见的好处是把上线的代码都通过版本记录,避免手动随意上传到线上的情况。

在测试服务器中运行gitlab-ci,实现不用每次手动build然后上传测试服务器再然后测试的目的,改进后的流程是push到服务器后自动发布更新。其中执行runner的配置,可以指定tag的runner,用来区分生产环境和非生产环境。也可以指定job对应的分支,用于区分测试分支或线上分支。

启动 gitlab-runner

查看gitlab-runner.sh的内容

$ cat gitlab-runner.sh

输出

docker run -d --name gitlab-runner -v /var/run/docker.sock:/var/run/docker.sock --restart always gitlab/gitlab-runner:latest

docker exec -it gitlab-runner gitlab-runner register --docker-volumes /data/servers/pc-web/tomcat/webapps/ROOT:/deployment --url http://git.example.com/

运行一个container

$ sudo sh gitlab-runner.sh

gitlab-runner 配置

第一步进入gitlab-runner运行的container

# docker exec -it gitlab-runner bash

第二步在gitlab-runner运行的container中,注册runner并且修改配置文件/etc/gitlab-runner/config.toml,修改volumes配置项,将host机的目标文件夹挂载至docker中。

由于我们运行gitlab-runner时,指定了docker.sock为宿主机,所以当在gitlab-runner中运行docker时,其实是在宿主机中运行docker,gitlab-runner中docker的运行container和gitlab-runner的container都在宿主机中且是并列关系,此处没有用到docker in docker。但gitlab-runner中运行docker的配置文件,还需要在gitlab-runner的container中修改。

# gitlab-runner register
# vim /etc/gitlab-runner/config.toml
# cat /etc/gitlab-runner/config.toml

输出结果

concurrent = 1
check_interval = 0

[[runners]]
  name = "simple"
  url = "http://git.example.com/"
  token = "07aa49d672287791eaccbf7fdc3f74"
  executor = "docker"
  [runners.docker]
    tls_verify = false
    image = "node:8"
    privileged = false
    disable_cache = false
    volumes = ["/data/servers/pc-web/tomcat/webapps/ROOT:/deployment/", "/cache"]
    shm_size = 0
  [runners.cache]

修改/etc/gitlab-runner/config.toml配置后,gitlab-runner会自动更新。可以运行sudo docker logs -f gitlab-runner查看gitlab-runner的运行日志。

gitlab-ci 配置

源码中.gitlab-ci.yml配置如下

 image: node:8

 cache:
   paths:
     - node_modules/

 before_script:
   - node -v
   - npm install -g cnpm --registry=https://registry.npm.taobao.org
   - cnpm -v
   - cnpm install

 deploy:
   script:
     - ls -lh /deployment/myproject
     - npm run build
     - ls -lh build
     - cp -r build/* /deployment/myproject

前端持续集成就是这么👌。

wisetc commented 6 years ago
image: wisetc/cnode:8

before_script:
  - cd project

stages:
  - setup
  - test
  - deploy

cache:
  key: pc-refactor
  paths:
    - node_modules/
  untracked: true

setup:
  stage: setup
  script:
    - cnpm -v
    - cnpm install
  only:
    - test
  tags:
    - node

test:
  stage: test
  script:
    - npm test
  tags:
    - node
  only:
    - test

deploy:
  stage: deploy
  script:
    - npm run build
    - ls -lh dist
    - ls -lh /deployment/admin
    - rm -rf /deployment/admin/*
    - cp -r dist/* /deployment/admin
  only:
    - test
  tags:
    - h5test
wisetc commented 6 years ago

相关重要文档链接列下

wisetc commented 5 years ago

package.json中新增了项目依赖,怎么清除 runner 的缓存?

runner 的缓存一般 docker container 名以 -cache- 为标记。

docker ps -f status=exited  | grep "\-cache-" | awk '{print $1}' | xargs docker rm
wisetc commented 5 years ago

Gitlab runner 运行于 container 中,怎么在该构建系统中使用 SSH keys?

Gitlab 目前并不内置对在 gitlab runner 中管理 SSH keys 的支持,但是可以利用 Gitlab 变量将 SSH keys 注入 runner 的环境中,然后在该 runner 环境中使用 ssh-agent 来代理 ssh。

将 SSH 私钥 ~/.ssh/id_rsa 的内容保存在 Gitlab 的设置中的 Settings / Pipelines / Secret variables,名称为 SSH_PRIVATE_KEY

image

然后配置好 .gitlab-ci.yml,如下示例,

deploy:
  stage: deploy
  before_script:
    - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - ssh-keyscan -p $SSH_PORT $SSH_SERVER >> ~/.ssh/known_hosts
    - chmod 644 ~/.ssh/known_hosts
    - ssh -p $SSH_PORT -T sftp@$SSH_SERVER
  script:
    - REACT_APP_PASSWORD=sample_passwd npm run build
    - ls -lh build
    - hostname
    - scp -P $SSH_PORT -r ./build/* sftp@$SSH_SERVER:$DEPLOYE_PATH
  only:
    - master
  tags:
    - node

参考:

wisetc commented 5 years ago

如何在服务器上调试 gitlab-runner?

进入服务器后,切换到项目目录,将远程仓库的代码拉取至服务器,修改项目的 .gitlab-ci.yml 文件,假设 job 名称为 setup,可以通过如下的命令运行该 yaml 文件中的 setup,

$ gitlab-runner exec docker setup

参考:

wisetc commented 5 years ago

如何为每一个分支甚至每一次版本构建一个独立的发布?假设 docker 映射目录为 /deployment,Vue 项目打包的后生成的待发布的文件夹名为 dist, 所有的开发分支的名称为类似dev*,可以参考如下的示例。


deploy_dev_test:
  stage: deploy_dev_test
  before_script:
    - cd project
    - export DOCKER_MAPPING_DEPLOY_VOLUME="/deployment"
    - export PROJECT_DEPLOY_DIR_NAME_CURRENT="$DOCKER_MAPPING_DEPLOY_VOLUME/$CI_PROJECT_NAME/$CI_COMMIT_REF_NAME/$(git log -1 --pretty='%h')"
    - export PROJECT_DEPLOY_DIR_NAME_LATEST="$DOCKER_MAPPING_DEPLOY_VOLUME/$CI_PROJECT_NAME/$CI_COMMIT_REF_NAME/latest"
    - mkdir -p $PROJECT_DEPLOY_DIR_NAME_CURRENT
    - mkdir -p $PROJECT_DEPLOY_DIR_NAME_LATEST
  script:
    - npm run build
    - ls -lh dist
    - cp -r dist/* $PROJECT_DEPLOY_DIR_NAME_CURRENT
    - ls -lh $PROJECT_DEPLOY_DIR_NAME_LATEST
    - rm -rf $PROJECT_DEPLOY_DIR_NAME_LATEST/*
    - cp -r dist/* $PROJECT_DEPLOY_DIR_NAME_LATEST
    - echo "http://example.com/$CI_PROJECT_NAME/$CI_COMMIT_REF_NAME/$(git log -1 --pretty='%h')"
    - echo "http://example.com/$CI_PROJECT_NAME/$CI_COMMIT_REF_NAME/latest"
  only:
    - /dev.*/
  tags:
    - h5test

打包后生成的链接如,

wisetc commented 4 years ago
// save_build.prod.js
// @format
const util = require('util');
const exec = util.promisify(require('child_process').exec);

async function getCommitMessage() {
  const { stdout } = await exec(
    'echo $(git log -1 --pretty="%B") | tr -d "\n"'
  );
  return stdout;
}

async function getAuthor() {
  const { stdout } = await exec(
    'echo $(git log -1 --pretty="%an <%ae>") | tr -d "\n"'
  );
  return stdout;
}

async function getHash() {
  const { stdout } = await exec(
    'echo $(git log -1 --pretty="%H") | tr -d "\n"'
  );
  return stdout;
}

async function getPostBody() {
  const content = await getCommitMessage();
  const creator = await getAuthor();
  const version = await getHash();
  const body = {
    content,
    creator,
    product: 'dingtalk',
    version,
  };
  let ret = '';
  for (const k in body) {
    let value = encodeURIComponent(body[k]);
    ret += `&${k}=${value}`;
  }
  return ret.slice(1);
}

async function saveBuild() {
  const postBody = await getPostBody();
  const url = process.env.BUILD_LOGGER_URL;
  const shellCmd = `curl "${url}" -d "${postBody}"`;
  console.log(shellCmd);
  const { stdout, stderr } = await exec(shellCmd);
  stdout && console.log(stdout);
  stderr && console.log(stderr);
  return stdout;
}

saveBuild();
wisetc commented 4 years ago

利用 ssh 发布 node server 应用。

# .gitlab-ci.yml
image: wisetc/cnode:8
stages:
  - deploy

deploy:
  stage: deploy
  before_script:
    - which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - ssh-keyscan -p $SSH_PORT $SSH_SERVER >> ~/.ssh/known_hosts
    - chmod 644 ~/.ssh/known_hosts
    - ping -c 4 $SSH_SERVER
    - ssh -p $SSH_PORT -T $SSH_USER@$SSH_SERVER
  script:
    - ls $DEPLOY_PATH
    - cp -R * $DEPLOY_PATH
    - ssh -p $SSH_PORT $SSH_USER@$SSH_SERVER "$START_COMMAND"
  tags:
    - node
    - production
    - server
  only:
    - master

其中 START_COMMAND 环境变量的配置例如下面的执行脚本,

cd /data/node-server/my-server; ls; docker-compose up -d --build
wisetc commented 1 year ago

gitlab 针对不同的文件修改指定不同的 Job,

dev-portal-deploy:
  stage: Deploy
  # image: xxx
  before_script:
    - pwd
  script:
    - 'which ssh-agent || ( sudo apt-get install -qq openssh-client )'
    - eval $(ssh-agent -s)
    - echo "$SSH_DEV_DEPLOY_KEY" | tr -d '\r' | ssh-add -
  only:
    refs:
      - dev
      - /^v1\./
    changes:
      - '.gitlab-ci.yml'
      - portal/**/*