前段时间一直使用drone来做敏捷开发,现在由于项目要求并不高,改为使用circleCI,记录一下使用的过程,也给需要了解的同学一些建议吧
前期
我是使用Bitbucket开发的,也不知道需要不需要过墙,反正我开电脑就开着梯子。如果有需要了解github的同学也可以瞧瞧,不妨碍。
添加项目的一些操作就不聊了,下面主要说说配置文件的事情。
概念
Orbs
orbs是项目之间共享配置包。
Jobs
Jobs是一系列的步骤,job里的所有步骤都是circleCI容器中的独立单元。
Steps
Steps是在job运行期间的可执行命令的集合。
安全策略
SSH和HTTPS技术来加密网络请求和服务。所有jobs都在一个沙箱内工作,外网无法访问。通过SSH来获取执行代码,特定的测试和配置文件会从外网获取到沙箱内供代码使用。job完成后会销毁相关的容器,下个任务会重新构建。环境变量通过Hashicorp Vault加密,采用AES256-GCM96加密变量,CircleCI无法获取。
提示:用户可以完全访问在构建容器中运行的任何文件或进程,因此仅向那些信任您的源代码的用户提供对CircleCI的访问权限。
采用的第三方技术
采用Pusher来完成服务跟游览器的交互任务。在安装Pusher时采用了slanger封装,所以Pusher服务无法访问CircleCI或者您的代码。
采用Replicated管理CircleCI的安装向导,许可密钥,系统审核日志,软件更新以及其他维护和系统任务
审核日志事件
这部分内容是部署到自己的服务或者私有云上的,这里就不谈了。
开始 (适用于2.0以上版本)
具体的等级结构:
version
orbs
(requires version: 2.1)commands
(requires version: 2.1)executors
(requires version: 2.1)-
jobs
- <
job_name
>environment
parallelism
docker
/machine
/macos
(executor)branches
resource_class
-
steps
-
run
- Default shell options
- Background commands
- Shorthand syntax
- The
when
Attribute - Example
- The
when
Step (requires version: 2.1)- Example
checkout
setup_remote_docker
-
save_cache
- Example
-
restore_cache
- Example
-
deploy
- Example
-
store_artifacts
- Example
-
store_test_results
- Example
persist_to_workspace
- Example for root Key
- Example for paths Key
-
attach_workspace
- Example
add_ssh_keys
-
- <
-
workflows
version
- <
workflow_name
>-
triggers
-
schedule
cron
filters
-
-
jobs
- <
job_name
>requires
context
type
filters
- Example
- <
-
1.项目根目录下需要如下格式的配置文件
mkdir .circleci && touch .circleci/config.yml
2.版本声明
version: 2.1 //版本号
3.orbs 配置包管理 这个包管理是2.1的特性 2.1以下无法使用
version: 2.1
orbs:
hello: circleci/[email protected]
workflows:
"Hello Workflow":
jobs:
- hello/hello-build
4.commands sh指令 版本2.1以上
commands:
sayhello:
description: "A very simple command for demonstration purposes"
parameters:
to:
type: string
default: "Hello World"
steps:
- run: echo << parameters.to >>
- executors 执行单元 自定义的执行沙盒(容器) 2.1以上
version: 2.1
executors:
my-executor:
docker:
- image: circleci/ruby:2.5.1-node-browsers
jobs:
my-job:
executor: my-executor
steps:
- run: echo outside the executor
- jobs 工作单元
jobs:
build:
docker:
- image: buildpack-deps:trusty
environment:
FOO: bar
parallelism: 3
resource_class: large
working_directory: ~/my-app
branches:
only:
- master
- /rc-.*/
steps:
- run: make test
- run: make
Jobs 是用map指定的,job的名字就是map的key值,如果你使用Workflows,jobs的名字必须保持唯一。如果没有使用workflows,就必须包含build这个key。build是版本控制push时的默认入口,然后再开始其他的工作。
jobs的最大工作时间是5小时,超过这个时间你就得考虑使用并行模式。
job的参数说明:
docker
: 指定容器的配置。
machine
: 虚拟机。
macos
: iOS运行机。
executor
:docker
,machine
,macos
这三个只能设置一个,多个会报错。
shell
: 所有steps都需要运行的shell指令,会被steps里的shell覆盖。
steps
: 需要执行的步骤列表。
working_directory
: 在哪个目录下运行你的steps
。
parallelism
: 要运行的此job的并行实例数,一般情况下是1,更多就得花钱买。
environment
: 环境变量。
branches
: 分支管理,白名单和黑名单。
resource_class
: 资源分配,分配多少CPU等。只有付费用户才有的特性。
docker
executor
就是steps
运行的地方。CircleCI可以一次性运行多个容器,或者使用整个虚拟机。
docker
使用的key包括:
image
: 容器的镜像。
name
: 容器的名字 可以通过名字来访问其他容器 默认是localhost。
entrypoint
: 容器启动时执行的指令。
command
: 作为为entrypoint的参数或者没有entrypoint直接执行命令 参考docker设计理念。
user
: 容器内执行程序的用户名称。
environment
: 环境变量 这个优先级高于外面job声明的。
auth
: docker login
的登录凭证。
aws_auth
: AWS EC2容器仓库的登录凭证。
典型的栗子
jobs:
build:
docker:
- image: buildpack-deps:trusty # primary container
environment:
ENV: CI
- image: mongo:2.6.8
command: [--smallfiles]
- image: postgres:9.4.1
environment:
POSTGRES_USER: root
- image: redis@sha256:54057dd7e125ca41afe526a877e8bd35ec2cdd33b9217e022ed37bdcf7d09673
如果你使用私人镜像,提供登录凭证就行了,这个参数的值可以在CircleCI的后台游览器里进行设置。
jobs:
build:
docker:
- image: acme-private/private-image:321
auth:
username: mydockerhub-user # can specify string literal values
password: $DOCKERHUB_PASSWORD # or project UI env-var reference
在容器内部可以重用外部的commands指令。
jobs:
myjob:
docker:
- image: "circleci/node:9.6.1"
steps:
- sayhello:
to: "Lev"
machine
不谈了,说白了就是主机模式,就是运行了一个ubuntu镜像的容器,容器里有docker、docker-compose。详细了解的可以到 machine executor。
version: 2
jobs:
build:
machine:
image: circleci/classic:201708-01
macos
iOS macOS tvOS watchOS平台所用的
jobs:
build:
macos:
xcode: "9.0"
branches
定义分支的黑白名单(没有使用Workflows并且是2.0)如果你使用Workflows,只会执行workflows中定义的branches,如果你使用2.1,你必须得用workflows。
栗子:
jobs:
build:
branches:
only:
- master
- /rc-.*/
jobs:
build:
branches:
ignore:
- develop
- /feature-.*/
resource_class
(付费节目 不谈)。
steps
先把栗子甩出来:
jobs:
build:
working_directory: ~/canary-python
environment:
FOO: bar
steps:
- run:
name: Running tests
command: make test
steps应该是单一的键值对,key是代表step类型。这里的run只是一个step类型(step_type下面会讲更多的step类型),name是为了说明这个step是干嘛的,会在后台ui上输出,command就是sh指令。
jobs:
build:
steps:
- run: make test
这个是缩写模式,name就是make test。还有一种缩写模式。
jobs:
build:
steps:
- checkout
step_type: run
command
通过shell运行的指令。
name
step的名称。
shell
执行指令的shell。
environment
command的环境变量。
background
是否后台运行。
working_directory
目录 默认是job的。
no_output_timeout
没有输出情况下运行的时间 就是延时。
when
什么时候开启和关闭step 值有always
, on_success
, on_fail
。
每一个run都会生成一个shell,一个run的多个command都是在一个shell工作的
- run:
command: |
echo Running test
mkdir -p /tmp/test-results
make test
默认的shell是这个:
/bin/bash -eo pipefail
如果命令返回非0值,会跳出报错,steps也走不下去。如果需要忽略指令的结果,可以主动修改shell,或者按照如下的set指令来修改,不过推荐使用默认的,因为这样你就能看到错误信息了。
- run:
command: |
echo Running test
set +e
mkdir -p /tmp/test-results
make test
- run:
shell: /bin/sh
command: |
echo Running test
mkdir -p /tmp/test-results
make test
一些简单的缩写格式
- run: make test
# shorthanded command can also have multiple lines
- run: |
mkdir -p /tmp/test-results
make test
when
这个值很有意思,如果前面的step出现了错误,后面的step就不会执行(on_success)。如果你指明when为always的话,则这个step怎么都会执行的,on_fail只会前面有错误才执行,这对错误收集有作用。
steps:
- run:
name: Testing application
command: make test
shell: /bin/bash
working_directory: ~/my-app
no_output_timeout: 30m
environment:
FOO: bar
- run: echo 127.0.0.1 devhost | sudo tee -a /etc/hosts
- run: |
sudo -u root createuser -h localhost --superuser ubuntu &&
sudo createdb -h localhost test_db
- run:
name: Upload Failed Tests
command: curl --data fail_tests.log http://example.com/error_logs
when: on_fail
when
注意这个when是跟run同级别的 上面那个when是run的子key(2.1的新特性,2.1干了很多控制方面的事情)
先睹栗子
version: 2.1
jobs: # conditional steps may also be defined in `commands:`
job_with_optional_custom_checkout:
parameters:
custom_checkout:
type: string
default: \"\"
machine: true
steps:
- when:
condition: <>
steps:
- run: echo \"my custom checkout\"
- unless:
condition: <>
steps:
- checkout
workflows:
build-test-deploy:
jobs:
- job_with_optional_custom_checkout:
custom_checkout: \"any non-empty string is truthy\"
- job_with_optional_custom_checkout
这个不聊了 看栗子吧
checkout
直接拉取代码,通过SSH方式
- checkout
- run: git submodule sync
- run: git submodule update --init
由于checkout不支持子模块,如果需要拉子模块跑git指令
setup_remote_docker
创建配置为执行Docker命令的远程Docker环境(付费节目)
save_cache
在我们的对象存储中生成并存储文件或文件目录的缓存,例如依赖项或源代码
restore_cache
基于key恢复以前保存的缓存
deploy
deploy使用与run步骤相同的配置映射和语义
store_artifacts
store_artifacts可在Web应用程序中或通过API提供的工件(例如日志,二进制文件等)
- store_artifacts:
path: /code/test-results
destination: prefix
store_test_results
用于上传测试结果的特殊步骤,以便在构建中显示
persist_to_workspace
用于持久保存临时文件以供工作流中的另一个作业使用的特殊步骤。
attach_workspace
用于将工作流的工作空间附加到当前容器的特殊步骤
add_ssh_keys
将SSH密钥从项目设置添加到容器的特殊步骤。还配置SSH以使用这些密钥
workflows
工作流程 编排jobs
整个配置文件
version: 2
jobs:
build:
docker:
- image: ubuntu:14.04
- image: mongo:2.6.8
command: [mongod, --smallfiles]
- image: postgres:9.4.1
# some containers require setting environment variables
environment:
POSTGRES_USER: root
- image: redis@sha256:54057dd7e125ca41afe526a877e8bd35ec2cdd33b9217e022ed37bdcf7d09673
- image: rabbitmq:3.5.4
environment:
TEST_REPORTS: /tmp/test-reports
working_directory: ~/my-project
branches:
ignore:
- develop
- /feature-.*/
steps:
- checkout
- run:
command: echo 127.0.0.1 devhost | sudo tee -a /etc/hosts
# Create Postgres users and database
# Note the YAML heredoc '|' for nicer formatting
- run: |
sudo -u root createuser -h localhost --superuser ubuntu &&
sudo createdb -h localhost test_db
- restore_cache:
keys:
- v1-my-project-{{ checksum "project.clj" }}
- v1-my-project-
- run:
environment:
SSH_TARGET: "localhost"
TEST_ENV: "linux"
command: |
set -xu
mkdir -p ${TEST_REPORTS}
run-tests.sh
cp out/tests/*.xml ${TEST_REPORTS}
- run: |
set -xu
mkdir -p /tmp/artifacts
create_jars.sh ${CIRCLE_BUILD_NUM}
cp *.jar /tmp/artifacts
- save_cache:
key: v1-my-project-{{ checksum "project.clj" }}
paths:
- ~/.m2
# Save artifacts
- store_artifacts:
path: /tmp/artifacts
destination: build
# Upload test results
- store_test_results:
path: /tmp/test-reports
deploy-stage:
docker:
- image: ubuntu:14.04
working_directory: /tmp/my-project
steps:
- run:
name: Deploy if tests pass and branch is Staging
command: ansible-playbook site.yml -i staging
deploy-prod:
docker:
- image: ubuntu:14.04
working_directory: /tmp/my-project
steps:
- run:
name: Deploy if tests pass and branch is Master
command: ansible-playbook site.yml -i production
workflows:
version: 2
build-deploy:
jobs:
- build
- deploy-stage:
requires:
- build
filters:
branches:
only: staging
- deploy-prod:
requires:
- build
filters:
branches:
only: master
写的比较粗糙,后期有时间再完善。