CircleCI-博客中文翻译-三-
CircleCI 博客中文翻译(三)
通过 AWS CDK | CircleCI 自动部署 AWS lambda 功能
本教程涵盖:
- 定义您的 AWS CDK 应用程序和 AWS Lambda 处理程序
- 手动构建和部署 CDK 应用程序
- 自动化部署
这是由两部分组成的系列教程的第一部分。您还可以学习如何使用 AWS CDK 来自动部署带有 Lambda 授权器的 REST APIs】。
当您构建基于云的应用程序时,您可以选择使用云提供商提供的 GUI(图形用户界面)或 CLI(命令行界面)来部署资源。这种方法在只有少量资源的情况下可以很好地工作,但是随着应用程序复杂性的增加,手动管理基础设施会变得很困难。
您可以使用像 Terraform 或 AWS CDK 这样的解决方案,让您以编程方式管理基础设施代码,而不是手动部署云资源。借助富有表现力的面向对象编程语言,AWS CDK 允许您使用现有的技能和工具来开发云基础设施,从而加快开发过程。使用 AWS CDK 消除了对上下文切换的需要,因为您可以使用相同的 IDE 和工具来定义基础结构代码和运行时代码。AWS CDK 还使您的代码与 git 工作流的集成更加容易,并允许您使用 CI/CD 管道来自动化部署过程。
在本教程中,我将指导您使用 AWS 云开发工具包(CDK)来部署一个与 AWS S3 和 AWS DynamoDB 交互的 AWS Lambda 函数。
先决条件
对于本教程,您需要在系统上设置 Node.js 来定义您的 AWS CDK 应用程序和 AWS Lambda 处理程序。您还需要在您的系统上安装 AWS CLI 和 AWS CDK CLI,以便您可以配置 AWS 凭据并手动构建您的 CDK 应用程序。您将需要一个用于部署应用程序的 AWS 帐户和一个用于自动化部署的 CircleCI 帐户。
下面是跟随本教程所需的所有东西的列表:
我们的教程是平台无关的,但是使用 CircleCI 作为例子。如果你没有 CircleCI 账号,请在 注册一个免费的 。
创建新的 AWS CDK 项目
首先,为您的 CDK 项目创建一个新目录,并导航到其中。
mkdir aws-cdk-lambda-circle-ci
cd aws-cdk-lambda-circle-ci
接下来,使用 CDK CLI 运行cdk init
命令,这将使用 TypeScript 创建一个新的 CDK 项目。app
参数指定初始化项目时使用的模板。
cdk init app --language typescript
执行此命令会创建一个新的 CDK 项目,其中包含几个文件。在本教程的后面,我将解释其中一些文件的重要性以及它们中定义的结构。
注意: CDK 支持 TypeScript、Python、Java、C#等多种语言。你可以选择使用任何你觉得舒服的语言。
添加 NodeJS Lambda 函数
在本节中,您将使用 Node.js 定义一个 AWS Lambda 函数。Lambda 函数演示了如何将 CSV 文件保存到 AWS S3 并向 DynamoDB 表中添加一个条目。
首先,在 CDK 项目的根目录下创建一个lambda
目录。在lambda
目录中,添加一个用于 lambda 处理程序的index.js
文件和一个用于定义依赖关系的package.json
文件。
在package.json
文件中,定义 NodeJS 项目的名称,并添加一些将被我们的处理程序使用的依赖项。以下是该文件应该包含的内容:
{
"name": "ddb-s3-lambda-function",
"version": "0.1.0",
"dependencies": {
"csv-stringify": "^6.0.5",
"fs": "0.0.1-security",
"uuid": "^8.3.2"
}
}
添加完依赖项后,运行lambda
目录中的npm install
命令来安装软件包。
接下来,在index.js
文件中,定义一个空函数。在本教程的后面部分,您将实现这个函数。
exports.handler = async function (event) {
}
现在,您可以开始实施了。创建一个包含虚拟数据的 CSV 文件,并将其保存为临时文件。将这段代码添加到您之前创建的index.js
文件的底部:
// add imports at the top of the file
var fs = require('fs');
const {stringify} = require('csv-stringify');
function writeCsvToFileAndUpload(filePath, objectKey) {
var data = getCsvData();
var output = stringify(data);
fs.writeFileSync(filePath, output);
// we will add the uploadFile method later
uploadFile(filePath, objectKey);
}
function getCsvData() {
// return some CSV data
return [
['1', '2', '3', '4'],
['a', 'b', 'c', 'd']
];
}
接下来,在index.js
文件中定义另一个函数,它采用本地文件路径和 S3 对象路径,并将文件上传到 AWS S3。
// add imports at the top of the file
const AWS = require('aws-sdk');
AWS.config.update({ region: 'us-west-2' });
const s3 = new AWS.S3();
const BUCKET_NAME = process.env.BUCKET_NAME
const uploadFile = (fileName, objectKey) => {
// Read content from the file
const fileContent = fs.readFileSync(fileName);
// Setting up S3 upload parameters
const params = {
Bucket: BUCKET_NAME,
Key: objectKey,
Body: fileContent
};
// Uploading files to the bucket
s3.upload(params, function (err, data) {
if (err) {
throw err;
}
console.log(`File uploaded successfully. ${data.Location}`);
});
return objectKey;
};
该函数读取本地文件的内容,并使用AWS.S3
SDK 的upload
函数上传文件。
最后,添加您在index.js
文件中创建的空 AWS Lambda 处理程序的实现。Lambda 处理程序在其事件参数中接收jobId
。处理程序首先将 CSV 文件上传到 AWS S3,然后用jobId
和上传对象的 S3 路径更新 DynamoDB 表。
//add import at the top of the file
const { v4: uuidv4 } = require('uuid');
var ddb = new AWS.DynamoDB();
const TABLE_NAME = process.env.TABLE_NAME
exports.handler = async function (event) {
try {
const uploadedObjectKey = generateDataAndUploadToS3()
const jobId = event['jobId']
var params = {
TableName: TABLE_NAME,
Item: {
'jobId': { S: jobId },
'reportFileName': { S: uploadedObjectKey }
}
};
// Call DynamoDB to add the item to the table
await ddb.putItem(params).promise();;
return {
"status": "success",
"jobId": jobId,
"objectKey": uploadedObjectKey
}
} catch (error) {
throw Error(`Error in backend: ${error}`)
}
}
const generateDataAndUploadToS3 = () => {
var filePath = '/tmp/test_user_data.csv'
const objectKey = `${uuidv4()}.csv`;
writeCsvToFileAndUpload(filePath, objectKey)
return objectKey
}
处理程序使用AWS.DynamoDB
SDK 的putItem
方法在 DynamoDB 表中插入一个新项目。
为应用程序定义 CDK 结构
现在您已经定义了 AWS Lambda 处理程序,您可以定义将在您的应用程序中使用的所有 CDK 构造。AWS CDK 构造是云组件,封装了配置细节和使用一个或多个 AWS 服务的粘合逻辑。CDK 为最常用的 AWS 服务提供了一个构造库。
使用app
模板生成 CDK 项目会创建lib/aws-cdk-lambda-circle-ci-stack.ts
文件。这个文件包含了AwsCdkLambdaCircleCiStack
类。使用此文件定义 CDK 构件。
// The snippet shows the original contents for reference. You do not need to replace the file contents.
import { Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
export class AwsCdkLambdaCircleCiStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
// we will add all the constructs here
}
}
接下来,检查您的应用程序需要什么。这些任务将在本教程的下一节中描述。
- 创建一个 AWS S3 存储桶来保存由 AWS Lambda 函数上传的 CSV 文件。
- 创建一个 DynamoDB 表,其中的
jobId
和对象键将由 AWS Lambda 函数更新。 - 定义一个将使用 S3 和 DymamoDB 表的 AWS Lambda 函数。确保 AWS Lambda 函数将
BUCKET_NAME
和TABLE_NAME
作为参数。 - 确保 AWS Lambda 函数有足够的权限对 S3 存储桶和 DymamoDB 表执行操作。
定义 AWS S3 时段
要定义一个 AWS S3 桶,需要添加一个 CDK 构造,在lib/aws-cdk-lambda-circle-ci-stack.ts
文件中定义的constructor
内创建一个 AWS S3 桶。AWS S3 时段名称在所有 AWS 帐户中都是唯一的,因此您需要为您的时段提供一个唯一的名称。
import { Stack,
StackProps,
//update the existing import to add aws_s3
aws_s3 as s3
} from 'aws-cdk-lib';
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
// we will add all the constructs here
// provide a unique name for your S3 bucket
const circleCiGwpBucket = new s3.Bucket(this, "circle-ci-gwp-bucket", {
bucketName: "<YOUR_BUCKET_NAME>",
});
}
此时,如果您尝试部署堆栈,它将简单地部署一个 CloudFormation 应用程序,并为您创建一个 AWS S3 存储桶。
定义一个 DynamoDB 表
要定义 DynamoDB 表,添加一个 CDK 构造,在lib/aws-cdk-lambda-circle-ci-stack.ts
文件中定义的constructor
内创建一个 DynamoDB 表。
import {
Stack,
StackProps,
aws_s3 as s3,
//update the existing import to add aws_dynamodb
aws_dynamodb as dynamodb
} from 'aws-cdk-lib';
constructor(scope: Construct, id: string, props?: StackProps) {
// other code //
//add the following construct after the existing code in the constructor
const circleCiGwpTable = new dynamodb.Table(this, "CircleCIGwpTable", {
tableName: "CircleCIGwpTable",
partitionKey: { name: "jobId", type: dynamodb.AttributeType.STRING },
});
}
表名在您的 AWS 帐户中必须是唯一的。如果您的 AWS 帐户中已经有一个名为CircleCIGwpTable
的表,那么在定义 DynamoDB 构造时更新tableName
。
注意,您已经将jobId
定义为表的主分区键。这将确保jobId
值在表中是唯一的。
定义 AWS Lambda 函数
要定义一个 AWS Lambda 函数,添加一个 CDK 构造,在lib/aws-cdk-lambda-circle-ci-stack.ts
文件中定义的constructor
内创建一个 AWS Lambda 函数。AWS Lambda 函数将使用 NodeJS 运行时,并将使用我们在lambda
目录中定义的代码。此外,S3 桶名称和 DynamoDB 表名称将作为环境变量传递给该函数。
import {
Stack,
StackProps,
aws_s3 as s3,
aws_dynamodb as dynamodb,
//update the existing import to add aws_lambda and Duration
aws_lambda as lambda,
Duration
} from 'aws-cdk-lib';
constructor(scope: Construct, id: string, props?: StackProps) {
// other code //
//add the following construct after the existing code in the constructor
const circleCiGwpLambda = new lambda.Function(
this,
"CircleCiGwpLambda",
{
runtime: lambda.Runtime.NODEJS_14_X,
handler: "index.handler",
timeout: Duration.seconds(30),
code: lambda.Code.fromAsset("lambda/"),
environment: {
TABLE_NAME: circleCiGwpTable.tableName,
BUCKET_NAME: circleCiGwpBucket.bucketName
},
}
);
}
这个代码片段指定 AWS Lambda 函数的超时是 30 秒。Lambda 函数的最长执行时间可达 15 分钟。
授予 AWS Lambda 函数权限
最后,授予 AWS Lambda 函数足够的权限。Lambda 函数需要对 S3 对象的putObject
权限。通过在lib/aws-cdk-lambda-circle-ci-stack.ts
的构造函数中的现有代码后添加以下构造来授予这些权限:
circleCiGwpBucket.grantPut(circleCiGwpLambda);
Lambda 函数还需要对 DynamoDB 表的读/写权限。在lib/aws-cdk-lambda-circle-ci-stack.ts
的构造函数中的现有代码后添加以下构造:
circleCiGwpTable.grantReadWriteData(circleCiGwpLambda);
您可以使用 AWS CDK IAM 模块定义更复杂的 IAM 策略。
部署 CDK 堆栈
现在,您已经在堆栈中定义了 CDK 构造,您可以将应用程序部署到 AWS 帐户。首先手动部署项目,确保一切正常。然后,一旦您验证了它的功能,您就可以使用 CircleCI 自动化部署。
在第一次部署项目之前,您需要使用cdk
CLI 引导项目。应用程序的引导提供了 AWS CDK 部署应用程序可能需要的资源。这些资源可能包括用于存储部署相关文件的 S3 存储桶和用于授予部署权限的 IAM 角色。从项目的根目录发出以下命令:
cdk bootstrap
确保您在系统上配置了 AWS 凭据。如果配置了凭据,CDK 将自动使用它。
接下来,将应用程序部署到 AWS 帐户。
cdk deploy
执行该命令后,可能会提示您确认将应用于您的帐户的 IAM 角色/策略更改。如果您的应用程序设置正确,并且您的系统具备所有的先决条件,那么部署应该会成功。
使用 CircleCI 自动部署应用程序
现在您已经使用命令行手动部署了 CDK 应用程序,您可以自动化工作流了。自动化工作流意味着,每当您将代码推送到主分支时,基础结构的变更可以被自动打包和部署。您需要完成以下任务:
- 更新
.gitignore
- 更新 NPM 脚本
- 添加配置脚本
- 创建 CircleCI 项目
- 设置环境变量
更新。gitignore
由cdk init
命令生成的代码包含一个默认忽略所有.js
文件的.gitignore
文件。用以下代码片段替换.gitignore
的内容:
!jest.config.js
*.d.ts
node_modules
# CDK asset staging directory
.cdk.staging
cdk.out
更新 NPM 脚本
CircleCI 部署配置使用 NPM 脚本来执行deploy
和diff
命令。将这些脚本添加到根级package.json
文件中:
// update the aws-cdk-lambda-circle-ci/package.json file with the following scripts
{
...
"scripts": {
...
// add the ci_diff and ci_deploy scripts
"ci_diff": "cdk diff -c env=${ENV:-stg} 2>&1 | sed -r 's/\\x1B\\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g' || true",
"ci_deploy": "cdk deploy -c env=${ENV:-stg} --require-approval never"
},
...
}
添加配置脚本
首先,在包含 CI 管道配置文件的项目根目录中添加一个.circleci/config.yml
脚本。将以下代码片段添加到其中:
version: 2.1
orbs:
aws-cli: circleci/aws-cli@2.0.6
executors:
default:
docker:
- image: 'cimg/node:14.18.2'
environment:
AWS_REGION: 'us-west-2'
jobs:
build:
executor: 'default'
steps:
- aws-cli/setup:
aws-access-key-id: AWS_ACCESS_KEY
aws-secret-access-key: AWS_ACCESS_SECRET
aws-region: AWS_REGION_NAME
- checkout
- run:
name: 'install_lambda_packages'
command: |
cd lambda/authorizer && npm install
cd ../../
cd lambda/processJob && npm install
cd ../../
- run:
name: 'build'
command: |
npm install
npm run build
- run:
name: 'cdk_diff'
command: |
if [ -n "$CIRCLE_PULL_REQUEST" ]; then
export ENV=stg
if [ "${CIRCLE_BRANCH}" == "develop" ]; then
export ENV=prd
fi
pr_number=${CIRCLE_PULL_REQUEST##*/}
block='```'
diff=$(echo -e "cdk diff (env=${ENV})\n${block}\n$(npm run --silent ci_diff)\n${block}")
data=$(jq -n --arg body "$diff" '{ body: $body }') # escape
curl -X POST -H 'Content-Type:application/json' \
-H 'Accept: application/vnd.github.v3+json' \
-H "Authorization: token ${GITHUB_TOKEN}" \
-d "$data" \
"https://api.github.com/repos/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}/issues/${pr_number}/comments"
fi
- run:
name: 'cdk_deploy'
command: |
if [ "${CIRCLE_BRANCH}" == "main" ]; then
ENV=prd npm run ci_deploy
elif [ "${CIRCLE_BRANCH}" == "develop" ]; then
ENV=stg npm run ci_deploy
fi
CI 脚本使用 CircleCI 的 aws-cli orb 来设置 aws 配置——访问密钥和密码。build
作业有几个不同的步骤,安装软件包,计算diff
,并部署变更。cdk_diff
步骤只在拉请求时执行,并在 PR 上添加一个总结基础设施变更的注释。
cdk_deploy
命令检查分支并仅在prd
或stg
环境中部署。cdk_deploy
命令执行package.json
文件中定义的ci_deploy
脚本。
管道配置将负责构建、打包和部署 CDK 堆栈到指定的 AWS 帐户。提交更改并将它们推送到 Github 存储库。
注意: 一定要把AWS_REGION
换成自己的地区,如果不一样的话。
为应用程序创建一个 CircleCI 项目
接下来,使用 CircleCI 控制台将存储库设置为 CircleCI 项目。在控制台的项目选项卡上,搜索 GitHub repo 名称。点击为您的项目设置项目。
系统将提示您手动添加新的配置文件或使用现有的配置文件。您已经将所需的配置文件推送到代码库,所以选择最快选项,并输入托管您的配置文件的分支的名称。点击设置项目继续。
完成设置将自动触发管道。管道将在第一次运行时失败,因为我们还没有定义环境变量。
设置环境变量
从项目仪表盘中点击项目设置,然后点击环境变量选项卡。点击添加环境变量。您应该已经创建了 AWS 访问密钥和密码,如本教程的先决条件中所述。将这些值分别作为AWS_ACCESS_KEY
和AWS_ACCESS_SECRET
相加。另外,将AWS_REGION_NAME
的环境变量设置为您希望部署应用程序的地区。
配置好环境变量后,再次运行管道。这一次它应该会成功构建。
结论
本教程向您展示了 AWS CDK 如何简化基础设施相关代码的管理。借助 AWS CDK,您可以使用自己熟悉的语言为应用程序提供资源。AWS CDK 允许您在定义应用程序时使用逻辑语句和面向对象的技术。此外,AWS CDK 使用行业标准协议使基础设施代码可测试。
本教程向您展示了定义 AWS Lambda 函数的一个非常常见的用例,该函数具有与其他 AWS 服务交互的包依赖关系。我希望您同意用所有 AWS 服务定义堆栈并使用这里概述的步骤授予它细粒度的权限是多么简单。你可以在 GitHub 上查看本教程中使用的完整的源代码。如果你想定义一个类似的堆栈,GitHub 项目也可以作为你的模板。
Vivek Kumar Maskara 是 JP 摩根的一名软件工程师。他喜欢写代码,开发应用程序,创建网站,并写关于他的经历的技术博客。他的简介和联系方式可以在maskaravivek.com找到。
将 Django 应用部署到 AWS Elastic Beanstalk | CircleCI
本教程涵盖:
- 在 AWS 上设置 Django 应用程序
- 使用弹性 Beanstalk 命令行界面
- 创建连续部署管道
您的软件开发团队有大量的工具可供他们使用。一些旧工具正在以新的方式使用,这激发了更多新工具的产生。例如,JavaScript 已经从一种用于增加网站交互性的语言发展成为一种满足前端和后端需求的全栈语言。JavaScript 为 Express、Nest.js 和许多其他技术铺平了道路。
正如开发团队现在可以用 JavaScript 构建 API 一样,他们也可以构建由 Python 支持的 web 应用程序。这得到了 Flask 和 Django 等成熟框架的支持。越来越多的工具提供商正在他们的服务中增加对基于 Python 的应用程序的支持。
在本文中,我将指导您将 Django 应用程序部署到 AWS Elastic Beanstalk。我们将使用 circle ciAWS Elastic Beanstalkorb 来处理认证和部署。
AWS Elastic Beanstalk 帮助您在 Amazon 云中部署和管理应用程序,而不必了解运行这些应用程序的基础设施。弹性 Beanstalk 降低了管理复杂性,而不会限制选择或控制。您只需上传您的应用程序,Elastic Beanstalk 就会自动处理容量供应、负载平衡、伸缩和应用程序健康监控等细节。
先决条件
除了对 Django 和 Python 有一个基本的了解之外,您还需要这些东西来从本教程中获得最大的收益:
我们的教程是平台无关的,但是使用 CircleCI 作为例子。如果你没有 CircleCI 账号,请在 注册一个免费的 。
克隆演示项目
通过运行以下命令克隆示例 Django 项目:
git clone https://github.com/CIRCLECI-GWP/django-exchange-api exchangeRateApi
接下来,转到上一个命令创建的新文件夹的根目录。通过运行以下命令设置项目:
cd exchangeRateApi
pip install -r requirements.txt
python manage.py runserver
默认情况下,您的申请将送达http://127.0.0.1:8000/
。您可以在该端点查看 JSON 响应。
审查部署策略
既然您已经在本地运行了应用程序,那么回顾一下您的部署策略是一个好主意。除了包含配置文件来设置 CircleCI 的部署之外,不需要对项目代码进行任何更改。
以下是部署策略步骤的列表:
- 将应用程序部署到 Elastic Beanstalk
- 创建一个配置文件以在 CircleCI 上构建应用程序
- 将项目推送到 GitHub 上的存储库中
- 在 CircleCI 建立项目
- 提供 Amazon 凭证并使用 AWS Elastic Beanstalk orb 进行身份验证
将应用部署到 Elastic Beanstalk
在项目目录中,创建一个名为.ebextensions
的新目录。
mkdir .ebextensions
在.ebextensions
目录中,创建一个名为django.config
的新文件,并将其添加到:
option_settings:
aws:elasticbeanstalk:container:python:
WSGIPath: exchangeRateApi.wsgi:application
WSGIPath 从包含您的 wsgi.py 脚本的目录开始。它将用于启动您的应用程序。
接下来,使用以下命令初始化您的 EB CLI 存储库:
eb init -p python-3.8 exchangeRatesApi
如果您在安装awsebcli
时没有提供访问 id 和密钥,您将看到类似如下的错误:
ERROR: The current user does not have the correct permissions.
Reason: Operation Denied. The security token included in the request is invalid.
You have not yet set up your credentials or your credentials are incorrect You must provide your credentials.
提供有效的aws-access-id
和aws-secret-key
来完成设置过程。如果您还没有,可以按照下一节中的步骤操作。
添加具有编程访问权限的用户
转到 AWS 添加用户页面。选择用户名和 AWS 访问类型。
选择访问键-编程访问,使用 CLI 访问您的 Beanstalk 环境。
接下来,选择用户的权限。
前面的截图显示了在 AWS Elastic Beanstalk 上管理应用程序的最低要求。
点击下一个两次,创建新用户。
您将收到一条成功消息以及您的用户凭据。该页面只显示一次,因此,记下访问密钥 ID 和秘密访问密钥。这些将在本教程的后面使用。您可以下载包含凭据的 CSV 文件。
使用这些凭证来验证awsebcli
并继续部署过程。
创造新环境
使用以下命令创建新环境:
eb create django-env
这创建了一个名为django-env
的弹性 Beanstalk 环境;大约需要五分钟。该过程完成后,您可以通过运行以下命令找到新环境的域:
eb status
域名是CNAME
属性的值。
一旦应用程序被部署,将CNAME
属性添加到exchangeRateApi/settings.py
中的ALLOWED_HOSTS
设置中。
ALLOWED_HOSTS = ['127.0.0.1', 'localhost','INSERT_YOUR_CNAME_HERE']
接下来,部署变更。因为您使用 git 进行版本控制,所以您需要在运行eb deploy
之前提交您的更改。
git add .
git commit -m "Add EBS config"
eb deploy
现在,再次运行eb status
命令。这一次,健康状态应该是绿色。将CNAME
属性粘贴到您的浏览器中,以查看您的 API。
创建 CircleCI 配置
在项目的根目录下,创建一个名为.circleci
的新文件夹。在该文件夹中,创建一个名为config.yml
的新文件,并添加以下内容:
version: 2.1
orbs:
python: circleci/python@2.0.3
eb: circleci/aws-elastic-beanstalk@2.0.1
jobs:
build:
description: "Setup Django application and run tests"
executor: python/default
steps:
- checkout
- python/install-packages:
pkg-manager: pip
- run:
name: "Run tests"
command: python manage.py test
workflows:
build-and-deploy:
jobs:
- build
- eb/deploy:
context: aws-credentials
application-name: exchangeRatesApi
environment-name: django-env
platform-version: python-3.8
requires:
- build
这个配置使用 CircleCI 提供的两个 orb。python
orb 提供了对 Python 环境(安装了 pip)的访问,该环境用于在将更新部署到 AWS 之前对其进行测试。所有这些都发生在build
工作中。eb
orb 将变更部署到您在前面的步骤中创建的环境中。
在工作流完成运行build
作业之后,来自eb
orb 的deploy
作业部署变更。requires
键确保build
任务首先运行。为作业指定了应用程序名称、环境名称和平台版本。名为aws-credentials
的上下文被传递给作业。您将在本教程的后面部分创建此上下文。
提交并将您的更改推送到 git:
git add .
git commit -am "Add CircleCI configuration"
git push origin main
添加 AWS 凭据的上下文
从您的 CircleCI 仪表板,进入组织设置页面。选择上下文,然后点击创建上下文按钮。为您的上下文输入一个唯一的名称。您的上下文出现在安全性设置为All members
的列表中。这意味着组织中的任何人都可以在运行时访问该上下文。正如本教程的.circleci/config.yml
配置中所指定的,上下文名称应该是aws-credentials
。
接下来,选择aws-credentials
上下文。
点击添加环境变量按钮,输入变量名和值。然后点击添加变量按钮保存。aws-credentials
上下文需要 3 个环境变量:
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
AWS_DEFAULT_REGION
AWS_DEFAULT_REGION
的值在项目的.elasticbeanstalk/config.yml
文件中指定,在global
部分下。
将应用程序连接到 CircleCI
接下来,您需要在 GitHub 上建立一个存储库,并将项目链接到 CircleCI。查看将项目推送到 GitHub 以获取指示。
登录您的 CircleCI 帐户。如果你注册了你的 GitHub 账户,你所有的库都可以在你项目的仪表盘上看到。
点击django-exchange
项目旁边的设置项目。
系统将提示您编写新的配置文件,或者在项目中使用现有的配置文件。选择现有的分支,并输入您的代码在 GitHub 上所在的分支的名称。点击设置项目。
您的第一个工作流将开始运行并成功完成。
要确认您的工作流程是否成功,您可以使用CNAME
属性在浏览器中打开新部署的应用程序。
结论
在本教程中,我向您展示了如何使用 GitHub、CircleCI 和 AWS Elastic Beanstalk 为 Django API 设置 CI/CD 管道。使用您在这里学到的知识,您可以实现 Python 项目自动化部署的最佳实践。这为您的团队创造了机会,如果他们觉得他们不能在自动化部署的项目中使用他们选择的编程语言。
本教程的全部代码可以在 GitHub 上找到。
Oluyemi 是一名拥有电信工程背景的技术爱好者。出于对解决用户日常遇到的问题的浓厚兴趣,他冒险进入编程领域,并从那时起将他的问题解决技能用于构建 web 和移动软件。Oluyemi 是一名热衷于分享知识的全栈软件工程师,他在世界各地的几个博客上发表了大量技术文章和博客文章。作为技术专家,他的爱好包括尝试新的编程语言和框架。
部署一个 dockerized。NET 核心应用到 Azure 容器实例| CircleCI
原文:https://circleci.com/blog/deploy-dockerized-dotnet-core-to-azure/
本教程涵盖:
- 对 ASP.NET 核心应用程序进行归档
- 创建连续部署配置来构建和部署容器映像
- 部署。NET 核心应用程序到 Azure 容器注册表
在本教程中,您将学习如何使用 Docker 构建一个定制的 ASP.NET 核心容器,并在 Azure Container Registry 上托管容器映像,Azure Container Registry 是微软拥有的一个平台,允许您在私有注册表中构建、存储和管理容器映像。
在本教程结束时,您将能够应用在此获得的知识,将 Microsoft Azure registry 上的容器映像与 web app 服务链接起来,并启动您的应用程序。您将了解如何确保由于对您的代码库所做的更改而构建的每个新容器图像将自动更新应用程序。
为此,我们将:
- 在Azure Container Registry(ACR)上创建一个注册表来托管我们的容器映像,并获取访问密钥
- 为项目创建一个容器映像,并在本地构建和运行该容器
- 将 Docker 映像发布到创建的 Azure 容器注册中心
- 创建一个 Azure web 应用程序,并将其与发布的容器图像链接
- 启用连续部署,并创建一个配置文件,以便在 CircleCI 上构建和部署我们的容器映像
- 将项目推送到 GitHub,并与 CircleCI 连接
- 将容器映像部署到 Azure 容器注册中心
先决条件
本教程需要以下内容:
我们的教程是平台无关的,但是使用 CircleCI 作为例子。如果你没有 CircleCI 账号,请在 注册一个免费的 。
克隆演示项目
在本节中,您将从 GitHub 上的存储库中克隆本教程的演示项目。从终端运行:
git clone https://github.com/yemiwebby/docker-dotnet-api.git
一旦该过程完成,您将把项目下载到一个docker-dotnet-api
文件夹中。我们将继续建立一个容器注册中心来托管将为我们的项目生成的容器映像。
创建 Azure 容器注册表
Azure 容器注册表存储了该项目的图像。要创建它,请转到 Azure 门户主页,然后单击创建资源。然后选择集装箱>集装箱登记处。
在注册表创建页面上,我使用了名称dotnetcoreapi
。你可以使用任何你想要的名字;只是记得在你跟随教程的时候用它来代替我的。接下来,输入注册表所需的详细信息。
点击审核+创建。您将被重定向到可以查看注册表信息的页面。然后,点击创建来设置一个新的注册中心实例。
从注册表中获取访问密钥
在本节中,您将在 Azure 容器注册表中启用 Docker 访问。这对于部署过程至关重要,因为它允许您通过 CLI 远程登录 Azure container registry 并向其推送映像。
要启用 Docker 访问,打开注册表,进入设置部分,点击访问键。
这将显示注册表名称和登录服务器。使用切换按钮启用管理员用户。然后,复制用户名和任何密码,最好是第一个。请将它放在手边,因为在教程的后面会用到它。
容器化应用程序
接下来,您将使用已经包含在克隆项目中的定制 Dockerfile 文件来构建一个容器映像。Dockerfile 具有安装所有项目依赖项、构建项目并运行它所需的命令。转到应用程序的根目录,打开 docker 文件,并确保它包含以下内容:
# Build Stage
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY . ./
RUN dotnet restore
RUN dotnet publish -c Release -o out
# Serve Stage
FROM mcr.microsoft.com/dotnet/aspnet:6.0
WORKDIR /app
COPY --from=build /src/out .
ENTRYPOINT [ "dotnet", "docker-dotnet-api.dll" ]
上面的文件中指定了两个不同的阶段:
Build
采用。NET SDK 来安装任何需要的依赖项,并在将项目发布到名为out
的文件夹之前编译项目。Serve
使用ASP.NET 核心运行时映像从指定的工作目录运行应用程序,在本例中是app
。
这有时被称为多级 Dockerfile 。它将开发和生产指令合并到一个 Dockerfile 文件中,降低了流程的复杂性。
建立码头工人形象
在本节中,您将使用上一步中的注册表 URL 来构建项目的 Docker 映像。运行以下命令:
docker build -t dotnetcoreapi.azurecr.io/dotnet-api:latest .
注意: 用您为注册表 URL 和登录服务器详细信息选择的名称替换dotnetcoreapi.azurecr.io
和dotnet-api
。
基于应用程序和 Dockerfile 文件的内容,这个命令将构建容器映像。因为它使用了您之前创建的注册中心名称和登录服务器,所以它可以很容易地将容器映像映射到 Azure 容器注册中心。
在本地运行 Docker 映像
现在您已经构建了本地版本的容器映像,通过运行以下命令确保它能够工作:
docker run -d -p 5001:80 dotnetcoreapi.azurecr.io/dotnet-api
该命令在后台运行容器,将容器 ID 打印到终端,并在端口5001
上运行应用程序。请访问http://localhost:5001/api/weather
查看。
将 Docker 映像部署到 Azure 容器注册表
下一步是登录 Azure 容器注册中心,并将容器映像推送到注册中心。从终端运行:
docker login -u DOCKER_USER -p DOCKER_PASS dotnetcoreapi.azurecr.io
如果需要,用您的注册表 URL 替换dotnetcoreapi.azurecr.io
。然后,用适当的值替换以下占位符:
DOCKER_USER
是容器注册表的用户名。DOCKER_PASS
是容器注册表的密码。
登录后,通过运行以下命令将映像推送到 Azure 注册表:
docker push dotnetcoreapi.azurecr.io/dotnet-api:latest
该映像将被部署到 Azure registry。
为容器创建 web 应用服务
接下来,您需要创建一个 Azure Web App ,并将其与容器映像连接。进入 Azure 门户主页,点击创建资源。
然后选择Containers>Web App for Containers来创建一个新的 Web App 服务实例。
您将被重定向到创建 Web 应用程序页面。选择 Azure 订阅和资源组。如果没有资源组,请创建一个新的资源组。确保选择了默认值Docker container
。
从 Docker 选项卡中,选择图像源及其 Docker 图像。
点击审核+创建。您将被重定向到一个页面,在该页面上您可以查看 web 应用程序的详细信息。点击创建来设置一个新的 Azure web 应用。
您可以访问 URL https://dotnet-core-api.azurewebsites.net/api/weather
来查看部署到 Azure 的应用。
在 Azure 上设置连续部署
每次你的 Docker 图片更新时,你都想让应用程序接收更新。为了确保这一点,您需要为 web app 服务启用连续部署。
单击 web 应用程序名称,然后转到部署部分。点击部署中心,然后向下滚动设置选项卡。通过选择单选按钮来打开连续部署。点击保存。
选择连续部署后,web 应用程序将触发的新部署。每次在 Azure Container Registry 上重新构建 Docker 映像时,都会调用. NET Core 应用程序。
使用 CircleCI 自动化部署
下一步是为 CircleCI 添加管道配置。该配置将自动测试并运行命令来构建容器映像并将其推送到 Azure 容器注册中心。
在项目的根目录下,打开.circleci/config.yml
文件并用以下内容更新它:
version: 2.1
orbs:
docker: circleci/docker@2.1.2
jobs:
build-docker-image:
executor:
name: docker/docker
tag: "3.6"
steps:
- checkout
- docker/install-docker-tools
- setup_remote_docker:
docker_layer_caching: true
- run:
name: Build and push Docker image
command: |
docker build -t dotnetcoreapi.azurecr.io/dotnet-api:latest .
docker login -u $DOCKER_USER -p $DOCKER_PASS dotnetcoreapi.azurecr.io
docker push dotnetcoreapi.azurecr.io/dotnet-api:latest
workflows:
build-and-deploy:
jobs:
- build-docker-image
这些脚本从 CircleCI 中拉入 Docker orb。他们使用它的执行器来安装 Docker 构建所需的工具,并将映像推送到 Azure 容器注册中心。
在 GitHub 上建立一个资源库,并将项目链接到 CircleCI。查看将您的项目推送到 GitHub 以获取指导。
与 CircleCI 连接
登录您的 CircleCI 帐户。如果你注册了你的 GitHub 账户,你所有的库都可以在你项目的仪表盘上看到。搜索docker-dotnet-api
项目。
点击设置项目按钮。将提示您是否已经在项目中定义了 CircleCI 的配置文件。输入分支名称(对于本教程,我们使用main
)。点击设置项目按钮完成该过程。
此构建将失败,因为它需要 Azure 容器注册表凭据,而您尚未添加它们。
创建环境变量
要解决凭证问题,请单击项目设置按钮,然后单击环境变量。添加这两个新变量:
DOCKER_USER
是容器注册表的用户名DOCKER_PASS
是容器注册表的密码。
点击从开始重新运行工作流程。
您的工作流将成功运行。您可以在本地对代码库进行一些更改,并将其推送到 GitHub,以进一步测试持续部署流程。
就是这样!
去网址查看直播 app: https://dotnet-core-api.azurewebsites.net/api/weather
。
注意: 请注意,您在 Microsoft Azure 上的 URL 应该与上面显示的不同。
结论
您刚刚学习了如何轻松地将 ASP.NET 核心应用程序 dockerize,将容器映像部署到 Microsoft Azure Container Registry,并在 web 服务上启动它。
有了 Azure web app 上启用的持续部署,你就可以确信,一旦你将新版本的容器映像推送到注册中心,应用就会一直自动更新。
我希望本教程对你有所帮助。访问样例库获取该项目的完整源代码。
Oluyemi 是一名拥有电信工程背景的技术爱好者。出于对解决用户日常遇到的问题的浓厚兴趣,他冒险进入编程领域,并从那时起将他的问题解决技能用于构建 web 和移动软件。Oluyemi 是一名热衷于分享知识的全栈软件工程师,他在世界各地的几个博客上发表了大量技术文章和博客文章。作为技术专家,他的爱好包括尝试新的编程语言和框架。
将 ASP.NET 核心应用程序构建并部署到 Azure | CircleCI
- 创建一个 Azure Web 应用程序和一个配置文件来构建它
- 在 GitHub 和 CircleCI 上设置项目
- 将项目部署到 Azure Web 应用程序
自动化新 web 应用程序的部署和特性更新的发布可以提高开发团队的生产力和效率。自动化还最大限度地减少甚至消除了重复的手动部署,手动部署会在开发过程的这一关键部分引入人为错误的风险。自动化是一个有价值的目标,但是开发人员使用的各种框架和语言会使自动化部署成为一个挑战。
微软 Azure Web Apps 是一个平台即服务 (PaaS) ,让你发布运行在多个框架上、用不同编程语言编写的 Web 应用。然后,您可以使用 CI/CD 工具来构建、测试和部署 web 应用程序,以获得更快的发布周期、更高效的开发和更高质量的代码。
在本教程中,我将向您展示如何建立一个连续的部署管道来将 ASP.NET 核心应用程序部署到 Azure Web App 服务。我们将使用 Azure CLI orb 进行身份验证,并直接部署我们的应用程序。
先决条件
您将需要这些来从本教程中获得最大收益:
我们的教程是平台无关的,但是使用 CircleCI 作为例子。如果你没有 CircleCI 账号,请在 注册一个免费的 。
克隆演示项目
您的第一步是使用 Git 克隆一个用 ASP.NET 核心构建的 API。运行以下命令:
git clone https://github.com/CIRCLECI-GWP/deploy-aspdotnetcore-to-azure.git
接下来,转到上一个命令创建的新文件夹的根目录。运行应用程序:
cd deploy-aspdotnetcore-to-azure
dotnet watch run
您可能会得到一个关于框架版本兼容性的错误。
默认情况下。NET framework 应用程序在构建它的版本上运行。演示应用程序是用 ASP.NET 核心版本3.1
构建的。如果您运行的是不同的版本,将会出现该错误。使用以下命令找出您的计算机上安装的版本:
dotnet --version
如果输出的版本不是版本3.1
,您可以修复它。转到应用程序的根目录,打开dotnet-core-sample.csproj
文件。像这样更新:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp6.0</TargetFramework>
</PropertyGroup>
</Project>
将6.0
替换为之前在您的终端上显示的版本。然后,用dotnet watch run
命令再次运行项目。
该应用将于http://localhost:5000
上线。导航到这个端点http://localhost:5000/weatherforecast
来查看 JSON 响应。
审查部署策略
既然您已经在本地运行了应用程序,那么回顾一下您的部署策略是一个好主意。除了包含配置文件来设置 CircleCI 的部署之外,不需要对项目代码进行任何更改。
按照时间顺序,我们将:
- 创建 Azure web 应用程序
- 创建一个配置文件以在 CircleCI 上构建应用程序
- 将项目推送到 GitHub 上的存储库中
- 在 CircleCI 建立项目
- 提供 Azure 凭据并使用 Azure CLI orb 进行身份验证
- 使用 Git 设置部署 URL
- 将我们的项目部署到 Azure Web App
创建 Azure web 应用程序
如果您还没有帐户,在 Azure 上创建一个帐户。然后转到你的 Azure 门户仪表板,点击创建资源来创建一个新的服务实例。
接下来,从热门列表中点击 Web 应用。
您将被重定向到创建 Web 应用程序页面。选择 Azure 订阅和资源组。如果尚未创建新的资源组,请创建一个。
现在,为您的 web 应用程序输入一个友好的、唯一的名称。对于本教程,我使用了dotnet-core-sample
。如上图所示,更新其他字段。
点击审核+创建,然后创建。Azure 正在设置 web 应用环境,请稍候。
一旦流程完成,您将拥有一个 web 应用程序来托管您的 ASP.NET 核心应用程序。
添加 CircleCI 配置文件
在这一步,我们将使用 Windows orb 和 Azure CLI orb 为 CircleCI 创建管道配置。
首先,在项目的根目录下创建一个名为.circleci
的文件夹。在新文件夹中,创建一个名为config.yml
的文件。在新文件中,添加:
version: 2.1
orbs:
azure-cli: circleci/azure-cli@1.2.0
windows: circleci/windows@2.2.0
jobs:
build:
description: Build application with Release configuration
executor:
name: windows/default
steps:
- checkout
- restore_cache:
keys:
- dotnet-packages-v1-{{ checksum "dotnet-core-sample.csproj" }}
- run:
name: "Install project dependencies"
command: dotnet.exe restore
- run:
name: "Build Application according to some given configuration"
command: dotnet.exe build --configuration Release
- run:
name: "Publish to a subfolder"
command: |
dotnet.exe publish --configuration Release --output WebAPIFolder
- persist_to_workspace:
root: ~/project
paths:
- WebAPIFolder
login-to-azure-and-deploy:
executor: azure-cli/azure-docker
steps:
- azure-cli/install
- azure-cli/login-with-user:
alternate-tenant: false
- attach_workspace:
at: ~/project
- run:
command: az webapp deployment source show --resource-group sample-dotnet-core --name sample-dotnet-core-application
- run:
name: "Deploy Web App to Azure"
command: |
az webapp deployment source config-local-git --resource-group sample-dotnet-core --name sample-dotnet-core-application
workflows:
build-and-deploy:
jobs:
- build
- login-to-azure-and-deploy:
requires:
- build
这种配置可能看起来有点复杂,所以我将尝试为您分解它。
首先,它定义并引入我们在这个项目中使用的 orb:
circleci/azure-cli@1.2.0
orb 用于安装、初始化和登录 Azure 命令行界面。Azure CLI 让您可以访问一组命令来创建和管理 Azure 资源。- orb 为您提供了构建 Windows 项目的工具,例如。Net 框架。
配置的下一部分指定了两个不同的作业:
build
login-to-azure-and-deploy
build
作业使用windows/default
执行器,它从 GitHub 中检查我们的项目,安装项目的依赖项,并将应用程序发布到一个名为WebAPIFolder
的新的子文件夹中。这个作业的另一个步骤是persist_to_workspace
,它使用工作区特性将数据从工作流中的特定作业移动到可能需要相同数据的后续作业。
在这种情况下,我们希望包含项目WebAPIFolder
的已发布版本的文件夹在下一个作业中可用,而不需要重新构建项目。
login-to-azure-and-deploy
作业使用azure-cli/default
来安装 Azure CLI,并提供认证 Azure 用户的步骤。然后,它会附加先前存储的文件夹。然后,该作业使用 Azure CLI 来配置将与我们的 Azure web 应用程序连接的 Git URL。
工作流的最后一部分指定在build
任务完成之前login-to-azure-and-deploy
不应该运行。
将应用程序连接到 CircleCI
下一步是在 GitHub 上建立一个资源库,并将项目链接到 CircleCI。查看将项目推送到 GitHub 以获取指示。
登录您的 CircleCI 帐户。如果你注册了你的 GitHub 账户,你所有的库都可以在你项目的仪表盘上看到。
点击dotnet-core-sample
项目旁边的设置项目。
用您的资源组替换资源组。
系统将提示您编写新的配置文件,或者在项目中使用现有的配置文件。选择现有的分支,并输入您的代码在 GitHub 上所在的分支的名称。点击走吧。
您的第一个工作流将开始运行:
- 工作会过去的
login-to-azure-and-deploy
将会失败
因为我们还没有指定 Azure 凭证,所以login-to-azure-and-deploy
作业将会失败。
要解决这个问题,创建一个 Azure 服务主体并添加输出作为环境变量。点击项目设置。
点击左侧工具条上的环境变量按钮,创建这些变量:
AZURE_SP_TENANT
是存储服务主体的租户 ID 的环境变量的名称。AZURE_SP
是存储服务主体全名的环境变量的名称。AZURE_SP_PASSWORD
是存储服务主体密码的环境变量的名称。
了解如何使用 Azure CLI 创建 Azure 服务主体。
回到仪表板。点击从失败的重新运行工作流程。
当构建完成运行时,您可以查看输出。
这是为您自动生成的本地 URL,用于部署到您的 Azure web 应用。网址的格式是https://<username>:<password>@sample-dotnet-core-application.scm.azurewebsites.net/sample-dotnet-core-application.git
。
下一步是创建您的部署凭证并更新配置文件。请注意,部署凭据与 Azure 身份验证凭据不同。
更新配置文件
在这一步中,您将更新配置文件,并使用 Git 部署到生成的 URL。首先,返回门户为部署创建一个新的凭证,这样 Git 就不会提示输入密码。
从侧面菜单栏中,点击部署中心,然后点击本地 Git / FTP 凭证。滚动到用户范围部分。
输入用户名或使用默认用户名。输入密码并再次输入以确认。
点击顶部的保存按钮。
将.circleci/config.yml
的内容替换为:
version: 2.1
orbs:
azure-cli: circleci/azure-cli@1.2.2
windows: circleci/windows@2.2.0
jobs:
build:
description: Build application with Release configuration
executor:
name: windows/default
steps:
- checkout
- restore_cache:
keys:
- dotnet-packages-v1-{{ checksum "dotnet-core-sample.csproj" }}
- run:
name: "Install project dependencies"
command: dotnet.exe restore
- run:
name: "Build Application according to some given configuration"
command: dotnet.exe build --configuration Release
- run:
name: "Publish to a subfolder"
command: |
dotnet.exe publish --configuration Release --output WebAPIFolder
- persist_to_workspace:
root: ~/project
paths:
- WebAPIFolder
login-to-azure-and-deploy:
executor: azure-cli/azure-docker
steps:
- azure-cli/install
- azure-cli/login-with-user:
alternate-tenant: false
- azure-cli/login-with-service-principal
- attach_workspace:
at: ~/project
- run:
command: az webapp deployment source show --resource-group sample-dotnet-core --name sample-dotnet-core-application
# - run:
# name: "Deploy Web App to Azure"
# command: |
# az webapp deployment source config-local-git --resource-group sample-dotnet-core --name sample-dotnet-core-application
- run:
name: "Deploy Web App to Azure"
command: |
az webapp deployment source show --resource-group sample-dotnet-core --name sample-dotnet-core-application
cd ~/project/WebAPIFolder/
git init
git config --global user.email "motukadominic@gmail.com"
git config --global user.name "dominicmotuka"
git add .
git commit -m "Deploy Azure Web Application"
git remote add azure https://$GIT_USERNAME:$GIT_PASSWORD@sample-dotnet-core-application.scm.azurewebsites.net/sample-dotnet-core-application.git
git push azure master --force
workflows:
build-and-deploy:
jobs:
- build
- login-to-azure-and-deploy:
requires:
- build
对配置文件的更新包括 Git,设置一个远程 URL 来引用我们之前生成的链接,并推送到 Azure。
用您之前在 Azure 中为本地 Git 创建的凭证替换GIT_USERNAME
和GIT_PASSWORD
占位符。
注意: 如果您在密码中使用了任何特殊字符(如@
或$
),将会出现错误。为了防止这种错误,请使用与其等效的 HTML 编码引用。
快好了!再一次把你的代码推给 GitHub。
测试应用程序
在https://dotnet-core-sample.azurewebsites.net/weatherforecast
访问您的应用程序。您的应用程序已部署。
结论
您和您的团队所使用的越来越多的框架和语言可能会阻止您迁移到完全自动化的部署过程。在本教程中,我们展示了您可以使用 Windows 和 Azure orbs 设置功能部署管道。该管道成功地将 ASP.NET 核心应用程序部署到 Azure Web Apps 托管平台。
与您的开发团队分享您的工作成果,开始关于用自动化取代手动部署的对话。即使部署一个复杂的应用程序也是可以完成的,更低的人为错误风险、更高的效率和更高质量的代码都是值得投资的。
我希望这篇教程对你有所帮助。完整的源代码可以在 GitHub 上找到。
Oluyemi 是一名拥有电信工程背景的技术爱好者。出于对解决用户日常遇到的问题的浓厚兴趣,他冒险进入编程领域,并从那时起将他的问题解决技能用于构建 web 和移动软件。Oluyemi 是一名热衷于分享知识的全栈软件工程师,他在世界各地的几个博客上发表了大量技术文章和博客文章。作为技术专家,他的爱好包括尝试新的编程语言和框架。
将 ASP.NET 核心应用程序自动部署到 Heroku | CircleCI
本教程涵盖:
- 设置示例 ASP.NET 核心项目
- 在 Heroku 上创建应用程序
- 配置您的 ASP.NET 部署管道
以其跨平台兼容性和优雅的结构而闻名,ASP.NET 核心是微软为构建现代网络应用而创建的开源框架。有了它,开发团队可以构建单一的 web 应用和任意大小和复杂度的 RESTful APIs。
得益于 CircleCI 改进的基础设施以及对 Windows 平台和技术的支持,为 ASP.NET 核心应用程序设置自动化部署流程变得更加容易。
本文将指导您将 ASP.NET 核心应用程序自动部署到 Heroku。
先决条件
以下是您需要从本教程中获得最大收益的项目列表:
我们的教程是平台无关的,但是使用 CircleCI 作为例子。如果你没有 CircleCI 账号,请在 注册一个免费的 。
克隆和运行演示 ASP.NET 核心项目
首先,您将从 GitHub 克隆一个用 ASP.NET 核心 MVC 构建的简单应用程序。为此,请输入以下命令:
git clone https://github.com/yemiwebby/dotnet-heroku-starter.git dotnet-heroku-demo-app
这会将 starter 应用程序下载到您的开发文件夹中名为dotnet-heroku-demo-app
的文件夹中(或者您运行命令的位置)。
接下来,进入新克隆的应用程序并运行该应用程序:
// Move into the project folder
cd dotnet-heroku-demo-app
// run the application
dotnet watch run
您可能会得到一个关于框架版本兼容性的错误。
发生此错误的原因是,默认情况下,. NET framework 应用程序在生成它的版本上运行。演示应用程序是用 ASP.NET 核心版本3.1
构建的。如果您运行的是不同的版本,将会出现该错误。通过运行以下命令,检查计算机上安装的当前版本:
dotnet --version
如果输出的版本不是版本3.1
,您可以通过编辑应用程序根目录中的demoDotnet.csproj
文件来修复它。像这样更新:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp5.0</TargetFramework>
</PropertyGroup>
</Project>
将5.0
替换为之前在您的终端上显示的版本。如果你有一个类似于a.b.c
的版本,你只需要在配置中添加a.b
。完成后,用dotnet watch run
再次运行项目。
导航至http://localhost:5000
,打开默认主页。
这里没发生什么事情。对 ASP.NET 核心应用程序默认主页上的内容做了一个小的修改。
现在,按下CTRL + C
停止应用程序运行。
在 Heroku 上创建应用程序
接下来您需要做的是在 Heroku 上创建一个新的应用程序。新的应用程序将托管和运行我们的 ASP.NET 核心应用程序。前往 Heroku 仪表盘开始。点击新增,然后点击新增 App 。在表单中填写您的应用程序和您所在地区的名称。
然后,点击创建 app 按钮。您将被重定向到新创建的应用程序的部署视图。
添加 ASP.NET 核心构建包
正如在 Heroku Buildpacks 页面上所详述的,Buildpacks 扩展了 Heroku 的构建系统,以支持您选择的任何编程语言。构建包也使二进制包对运行时可用。
为了在 Heroku 上成功运行这个项目,您需要添加一个 buildpack。为此,点击设置选项卡。在构建包部分,点击添加构建包按钮。
这将打开一个表单,您可以在其中选择一个官方支持的构建包,或者为您的构建包提供一个 URL。目前,Heroku 还没有官方支持的 ASP.NET 核心构建包。没关系,您可以提供. NET 核心构建包的 URL。将https://github.com/heroku-softtrends/heroku-buildpack-dotnetcore.git
粘贴到输入栏,点击保存更改。
我们最不需要的就是 API 密钥。您将使用此密钥和应用程序名称将您的 ASP.NET 部署管道连接到 Heroku。要获取您的 API 密钥,请打开帐户设置页面。
滚动到 API 键部分。
点击显示按钮,复制 API 密钥。将它保存在您以后可以轻松找到的地方。
添加 CircleCI 配置文件
接下来,我们需要为 CircleCI 添加 ASP.NET 部署管道配置。对于这个项目,管道将由安装项目的依赖项和为生产编译应用程序的步骤组成。
在项目的根目录下,创建一个名为.circleci
的文件夹。在该文件夹中,创建一个名为config.yml
的文件。在新创建的文件中,添加以下配置:
version: 2.1
orbs:
heroku: circleci/heroku@1.2.6
windows: circleci/windows@2.4.1
jobs:
build:
description: Build application with Release configuration
executor:
name: windows/default
steps:
- checkout
- restore_cache:
keys:
- dotnet-packages-v1-{{ checksum "demoDotnet.csproj" }}
- run:
name: "Install project dependencies"
command: dotnet.exe restore
- run:
name: "Build Application according to some given configuration"
command: dotnet.exe build --configuration Release
workflows:
heroku_deploy:
jobs:
- heroku/deploy-via-git
这个配置引入了 Heroku orb circleci/heroku
,它自动让我们访问一组强大的 Heroku 任务和命令。其中一个任务是heroku/deploy-via-git
,它直接从你的 GitHub repo 将你的应用程序部署到你的 Heroku 账户。它还引入了 Windows orb ,为您提供了构建 Windows 项目的工具,如通用 Windows 平台(UWP)应用程序、. NET 可执行文件或特定于 Windows 的项目(如。NET 框架)。
该配置指定了一个名为build
的作业。它使用windows/default
执行器,安装项目所需的所有依赖项,然后构建项目。
接下来,我们需要在 GitHub 上建立一个存储库,并将项目链接到 CircleCI。查看将您的项目推送到 GitHub 以获得逐步说明。
接下来,登录您的 CircleCI 帐户。如果你注册了你的 GitHub 账户,你所有的库都可以在你项目的仪表盘上看到。
点击为您的dotnet-heroku-demo-app
项目设置项目。
系统将提示您编写新的配置文件,或者在项目中使用现有的配置文件。选择现有选项。在 GitHub 上输入您的代码所在的分支的名称,然后点击设置项目按钮。
您的第一个工作流将开始运行,但会失败。
此部署过程失败,因为我们没有提供 Heroku API 密钥。我们现在可以解决这个问题。点击项目设置按钮,然后点击环境变量。添加这两个新变量:
HEROKU_APP_NAME
是 Heroku (dotnet-core-heroku-demo-app
)中的应用名称HEROKU_API_KEY
是您从帐户设置页面获取的 Heroku API 密钥
从失败的中选择重新运行工作流以重新运行 Heroku 部署。这一次,您的工作流将成功运行。
要确认工作流是否成功,您可以在浏览器中打开新部署的应用程序。您的应用程序的 URL 应该是这样的格式https://<HEROKU_APP_NAME>.herokuapp.com/
结论
在本教程中,我向您展示了如何轻松地将 ASP.NET 核心应用程序部署到 Heroku 平台。CircleCI 基础设施使使用现有工具快速处理部署变得容易,让您和您的团队有宝贵的时间专注于开发您的应用程序。
我希望本教程对你有所帮助。完整的源代码可以在 GitHub 上找到。
Oluyemi 是一名拥有电信工程背景的技术爱好者。出于对解决用户日常遇到的问题的浓厚兴趣,他冒险进入编程领域,并从那时起将他的问题解决技能用于构建 web 和移动软件。Oluyemi 是一名热衷于分享知识的全栈软件工程师,他在世界各地的几个博客上发表了大量技术文章和博客文章。作为技术专家,他的爱好包括尝试新的编程语言和框架。
将 FeathersJS 应用程序自动部署到 Heroku | CircleCI
本教程涵盖:
- 创建 FeathersJS API
- 在 Heroku 上创建和设置项目
- 自动部署到 Heroku
这是由两部分组成的系列之一。你还可以学习如何自动测试 FeathersJS 应用程序。
自动化不仅仅是构建解决方案来取代复杂或耗时的手动流程。正如流行的说法,“任何能够自动化的事情都应该自动化。”例如,将更新部署到应用程序可以而且应该是自动化的。在本教程中,我将向您展示如何设置一个 FeathersJS 应用程序到 Heroku 的免提部署。我将指导您实现一个持续部署(CD)管道,以便在推出更改时立即发布应用程序的更新。我们将使用的示例应用程序是一个管理测验问题的 API。它提供了创建、阅读、更新和删除测验问题的端点。
先决条件
开始之前,请确保您的系统上安装了以下项目:
通过运行以下命令安装 FeathersJS CLI:
npm install -g @feathersjs/cli
对于存储库管理和持续集成/持续部署,您需要:
我们的教程是平台无关的,但是使用 CircleCI 作为例子。如果你没有 CircleCI 账号,请在 注册一个免费的 。
为什么是费瑟斯和赫罗库?
FeathersJS 是一个轻量级 web 框架,用于使用 JavaScript 或 TypeScript 创建实时应用程序和 REST APIs。FeathersJS 工具集包括一个架构模式,它使得创建可伸缩的 REST APIs 和实时应用程序变得容易。您可以在几分钟内构建原型,在几天内构建生产就绪的应用。
Heroku 是一个平台即服务(PaaS ),使开发人员能够完全在云中构建、运行和操作应用程序。通过关注维护基于云的应用程序的更高要求方面,Heroku 允许开发人员专注于构建应用程序,而不是维护服务器。
入门指南
为项目创建新文件夹:
mkdir feathers_heroku
cd feathers_heroku
接下来,使用 Feathers CLI generate
命令生成一个新应用程序。
feathers generate app
对于这个项目,我们将使用 JavaScript。还有,我们只想做一个 REST API。回答 CLI 中的问题,如下所示:
? Do you want to use JavaScript or TypeScript? JavaScript
? Project name feathers-heroku
? Description
? What folder should the source files live in? src
? Which package manager are you using (has to be installed globally)? npm
? What type of API are you making? REST
? Which testing framework do you prefer? Jest
? This app uses authentication No
? Which coding style do you want to use? ESLint
在您做任何事情之前,更新索引页面,让访问者知道 API 正在构建中。在public/index.html
中,向main
元素添加一条“在建”消息:
<main class="container">
<!-- Image declaration-->
<h1 class="center-text">This API is under construction</h1>
<!-- Footer declaration-->
</main>
接下来,使用以下命令运行您的应用程序:
npm run dev
默认情况下,应用程序运行在端口 3030。在您的浏览器中输入http://localhost:3030/
即可访问。
配置 Heroku
下一步是在 Heroku 上创建一个新的应用程序。你可以从 Heroku 仪表盘上完成这项工作。点击新建,然后点击新建 App。如图所示填写表格。如果需要,您可以为应用程序使用不同的名称和地区。
点击创建应用按钮。然后,您将被重定向到新创建的应用程序的部署视图。
接下来,您需要添加一个构建包。点击设置选项卡。在构建包部分,点击添加构建包。
在打开的表单上,您可以选择一个官方支持的构建包,或者为您的构建包提供一个 URL。选择 nodejs 使用官方支持的 Heroku nodejs 构建包。点击保存修改。Node.js 将用于构建您的下一个部署。
您最不需要的就是 API 密钥。你要用这个把你的 CircleCI 管道连接到 Heroku。要获取 API 密钥,请打开账户设置页面,向下滚动到 API 密钥部分。
点击显示按钮,复制显示的 API 密钥。
配置 CircleCI
接下来,我们需要为 CircleCI 添加管道配置。对于这个项目,管道将由两个步骤组成:
- 打造。在这里,我们构建项目并安装项目依赖项。理想情况下,我们应该在这个阶段运行项目测试。然而,为了保持本教程的合理长度,我们将跳过测试。
- 部署到 Heroku 。如果构建阶段成功完成,您可以将最新的更改部署到 Heroku。
在项目的根目录下,创建一个名为.circleci
的文件夹。在其中,创建一个名为config.yml
的文件。在新创建的文件中,添加以下配置:
# Use the latest 2.1 version of CircleCI pipeline process engine.
version: 2.1
orbs:
heroku: circleci/heroku@1.2.6
node: circleci/node@4.7.0
jobs:
build:
executor: node/default
steps:
- checkout
- node/install-packages:
cache-path: ~/project/node_modules
override-ci-command: npm install
workflows:
sample:
jobs:
- build
- heroku/deploy-via-git:
force: true # this parameter instructs the push to use a force flag when pushing to the heroku remote, see: https://devcenter.heroku.com/articles/git
requires:
- build
这种配置吸引了 Heroku orb circleci/heroku
。这个球体给你提供了一套强大的 Heroku 任务和命令。其中一个任务是heroku/deploy-via-git
,直接从 GitHub repo 将您的应用程序部署到您的 Heroku 帐户。该配置使用 Node.js orb circleci/node
,它允许您在默认启用缓存的情况下安装包。
在配置中还指定了一个名为build
的任务,它检查最新的代码并安装在package.json
文件中指定的包。
最后,有一个工作流运行build
作业,然后是heroku/deploy-via-git
作业。注意,有一个requires
选项告诉 CircleCI 只有在构建工作完成后才运行deploy-via-git
。
接下来,在 GitHub 上建立一个存储库,并将项目链接到 CircleCI。看到这个帖子寻求帮助:把你的项目推到 GitHub 。
登录您的 CircleCI 帐户。如果你注册了你的 GitHub 账户,你所有的库都会显示在你项目的仪表盘上。
在您的feathers_heroku
项目旁边,点击设置项目。
CircleCI 检测项目中的config.yml
文件。点击使用现有配置,然后开始建造。您的第一个工作流将开始运行,但是,它将失败!这是可以预料的。
部署过程失败,因为您没有提供 Heroku API 密钥。现在就去解决它。点击项目设置按钮,然后点击环境变量。添加两个新变量如下:
HEROKU_APP_NAME
变量是 Heroku (deno-heroku-circleci
)中的 app 名称。HEROKU_API_KEY
变量是您从帐户设置页面检索的 Heroku API 密钥。
选择从失败的选项重新运行工作流,以重新运行 Heroku 部署。要确认工作流是否成功,您可以在浏览器中打开新部署的应用程序。应用程序的 URL 应该是这样的格式:https://<HEROKU_APP_NAME>.herokuapp.com/
。
你将会看到你正在建设的索引页面。
实现questions
服务
是时候添加功能来处理我们的 API 上的问题了。对于本教程,问题将包含这些属性的字段:
- 困难
- 问题
- 回答正确
创建问题时,默认情况下会分配一个唯一的主键。
使用以下命令创建数据库支持的服务:
feathers generate service
对于这项服务,使用NeDB
,只需按回车即可确认。使用Questions
作为服务名,并用默认值确认所有其他提示。只需按下回车:
? What kind of service is it? NeDB
? What is the name of the service? Questions
? Which path should the service be registered on? /questions
? What is the database connection string? nedb://../data
有了这个命令,FeathersJS 就为您的问题提供了 CRUD 操作所需的一切。此时,您已经有了一个包含这些端点的 API:
GET /questions
逐页列出所有问题。POST /questions
创建一个新问题。GET questions/123
返回 id 为 123 的问题的详细信息。您还可以在这个请求中包含查询:questions/123?difficulty=medium
。PATCH /questions/123
和PUT /questions/123
用 id 123 更新问题的细节。DELETE /questions/123
删除 id 为 123 的问题。
您可以为您的应用程序提供服务,并向任何端点发出请求。对于本教程,在使用新的 API 之前,先植入数据库并覆盖一些默认功能。
当您收到添加问题的请求时,您希望在将请求保存到数据库之前,只从请求中检索前面指定的三个值。通过覆盖create
服务方法来实现。打开src/services/questions/questions.class.js
并对其进行编辑以匹配以下代码:
// src/services/questions/questions.class.js
const { Service } = require("feathers-nedb");
exports.Questions = class Questions extends Service {
create(data, params) {
const { question, correctAnswer, difficulty } = data;
const quizData = { question, correctAnswer, difficulty };
return super.create(quizData, params);
}
};
接下来,创建一个播种器,为您提供一些示例问题。在src/services/questions
目录中,创建一个名为questions.seed.js
的新文件。将此代码添加到新创建的文件中:
// src/services/questions/questions.seed.js
exports.seedQuestions = [
{
difficulty: "medium",
question: "The HTML5 standard was published in 2014.",
correctAnswer: "True",
},
{
difficulty: "medium",
question:
"Which computer hardware device provides an interface for all other connected devices to communicate?",
correctAnswer: "Motherboard",
},
{
difficulty: "medium",
question: "On which day did the World Wide Web go online?",
correctAnswer: "December 20, 1990",
},
{
difficulty: "medium",
question: "What is the main CPU is the Sega Mega Drive / Sega Genesis?",
correctAnswer: "Motorola 68000",
},
{
difficulty: "medium",
question: "Android versions are named in alphabetical order.",
correctAnswer: "True",
},
{
difficulty: "medium",
question:
"What was the first Android version specifically optimized for tablets?",
correctAnswer: "Honeycomb",
},
{
difficulty: "medium",
question:
"Which programming language shares its name with an island in Indonesia?",
correctAnswer: "Java",
},
{
difficulty: "medium",
question: "What does RAID stand for?",
correctAnswer: "Redundant Array of Independent Disks",
},
{
difficulty: "medium",
question:
"Which of the following computer components can be built using only NAND gates?",
correctAnswer: "ALU",
},
{
difficulty: "medium",
question:
"What was the name of the security vulnerability found in Bash in 2014?",
correctAnswer: "Shellshock",
},
];
接下来,打开src/services/questions/questions.service.js
并编辑它以匹配以下代码:
// src/services/questions/questions.service.js
// Initializes the `Questions` service on path `/questions`
const { Questions } = require("./questions.class");
const createModel = require("../../models/questions.model");
const hooks = require("./questions.hooks");
const { seedQuestions } = require("./questions.seed");
module.exports = async function (app) {
const options = {
Model: createModel(app),
paginate: app.get("paginate"),
};
// Initialize our service with any options it requires
app.use("/questions", new Questions(options, app));
// Get our initialized service so that we can register hooks
const service = app.service("questions");
//get the total number of questions in the database
const { total: totalQuestions } = await service.find({
query: {
$limit: 0,
},
});
//seed the database if there are no questions saved
if (totalQuestions === 0) {
await seedQuestions.forEach((question) => {
service.create(question);
});
}
service.hooks(hooks);
};
请注意,该代码片段中的代码首先检查数据库中的问题数量,只有当没有问题时才播种。这可以防止种子程序在每次启动本地服务器时运行。
使用 Postman 测试 FeathersJS API
现在你可以用 Postman 来测试你的 API 了。
向http://localhost:3030/questions
发送一个POST
请求。
向http://localhost:3030/questions
发送GET
请求以检索问题列表。
整洁!最后,用最新的代码更新 git 存储库。不要忘记从索引页中删除“正在建设中”的消息。
git add .
git commit -m "Implement CRUD functionality for questions"
git push origin main
您的 CircleCI 构建再次运行,完成后,您的 Heroku 应用程序将更新为最新代码。干得好!
结论
在本教程中,我向您展示了如何使用 GitHub、CircleCI 和 Heroku 为 FeathersJS API 设置 CI/CD 管道。
通过自动化发布新特性的过程,生产环境中的人为错误风险大大降低。产品还增加了一定程度的质量保证,因为只有当新特性的行为符合预期时,才会部署新特性。也就是说,只有当他们通过了指定的测试用例。
这也有助于更有效的软件管理过程和更快乐的开发人员。重复的,平凡的方面是自动化的,所以你的团队可以专注于解决问题和创造。要了解持续集成和部署的更多好处,请访问什么是 CI/CD 管道。
本教程的全部代码可以在 GitHub 上找到。
Oluyemi 是一名拥有电信工程背景的技术爱好者。出于对解决用户日常遇到的问题的浓厚兴趣,他冒险进入编程领域,并从那时起将他解决问题的技能用于构建 web 和移动软件。Oluyemi 是一名热衷于分享知识的全栈软件工程师,他在世界各地的几个博客上发表了大量技术文章和博客文章。由于精通技术,他的爱好包括尝试新的编程语言和框架。
Oluyemi 是一名拥有电信工程背景的技术爱好者。出于对解决用户日常遇到的问题的浓厚兴趣,他冒险进入编程领域,并从那时起将他的问题解决技能用于构建 web 和移动软件。Oluyemi 是一名热衷于分享知识的全栈软件工程师,他在世界各地的几个博客上发表了大量技术文章和博客文章。作为技术专家,他的爱好包括尝试新的编程语言和框架。
使用浪子| CircleCI 构建和部署 Flutter 应用程序
Flutter 是 Google 提供的一个工具包,用于构建跨平台应用,包括 Android、iOS 和 web 应用。随着越来越多的应用程序使用 it 和 Dart(底层语言)编写,考虑开发人员如何将他们的代码打包并交付给用户变得越来越重要。利用 CircleCI 和浪子,这是一个相对简单的过程,可以自动化。
按照以下指南,可以安装并创建您的第一个应用程序:
默认的“hello world”应用程序就足够了。我们不会过多地处理应用程序本身。将其推送到 GitHub 上的一个存储库中。
确保您已设置好使用 Google Play 或 Apple App Store 发布应用程序,每个应用程序的步骤会有所不同,因此请务必遵循各个提供商概述的步骤。
阅读更多关于移动应用开发持续集成的信息。
机器人
当发布 Android 应用时,在实现浪子之前有一些要求需要满足。需要一个“上传密钥”,这样谷歌才能在接受应用之前验证其真实性。设置的步骤可以在这里找到。建议在构建 Android 应用程序时使用 AppBundles,因为它允许 Google 为不同的平台构建单独的 apk,同时保持文件大小不变。记下您保存key.jks
文件的位置。虽然它可以存在于您的主目录中,但是在配置key.properties
文件时,将它保存到项目中一个被 g it 忽略的目录中会很方便。
本指南中的两个东西需要作为环境变量添加到 CircleCI 中:key.properties
文件和key.jks
文件。这将允许持续集成管道正确构建和签署应用程序。因为一个文件需要换行,而另一个文件是二进制文件,所以建议在将它们作为环境变量添加之前对它们进行 base64 编码,以保留数据。
您可以通过运行以下命令对它们进行编码:
cat <file> | base64 -w 0 # -w 0 will ensure no newlines are present.
然后,可以在作业过程中使用以下命令重新添加这些文件:
echo "$ENV_VARIABLE_NAME" | base64 --decode > <file>
在创建 Android 设置时,您还需要设置一个浪子服务帐户。你可以在这里阅读更多关于的内容。请务必将您的服务帐户 JSON 文件放在手边。我们将很快将其添加到管道中。还要注意,命令应该从您的 Flutter 项目下的android
目录中运行。
添加浪子所需的服务帐户可以通过添加服务帐户 JSON 文件内容作为SUPPLY_JSON_KEY_DATA
环境变量来完成。这不要与SUPPLY_JSON_KEY
混淆,后者应该是文件的文件路径。
Fastlane
现在我们的环境变量已经就位,我们可以使用 Flutter 构建一个签名的.aab
文件,是时候告诉浪子如何为我们做这件事了。我们从安卓开始。打开android/fastlane/Fastfile
会显示一些构建 Android 应用的默认设置,但它们对我们的用例不起作用。我们在用颤动建造。
首先,我们来定义一个新的“车道”。这是浪子被调用时将执行的一组指令。目前,我们将把我们的应用推向“测试”频道,而不是生产。
desc "Deploy a new beta build to Google Play"
lane :beta do
end
这是一个车道的基本结构。接下来,我们要获取一个内部版本号,这是一个递增的数字,用作应用程序版本的参考(不同于面向用户的 semver)。
将以下内容添加到车道:
build_number = number_of_commits()
这确保了build_number
是对 Git 存储库进行提交的次数。这也可以在 Flutter 用来构建包的pubspec.yaml
文件中手动递增。
接下来,我们将做建筑。我们需要转到父目录,运行几个 shell 命令来获取我们的包,清理以前的构建(如果有的话),然后用我们的构建号构建 appbundle。
Dir.chdir "../.." do
sh("flutter", "packages", "get")
sh("flutter", "clean")
sh("flutter", "build", "appbundle", "--build-number=#{build_number}")
end
最后,我们可以发送到测试版频道的应用商店。
upload_to_play_store(track: 'beta', aab: '../build/app/outputs/bundle/release/app.aab')
最后,你的车道看起来会像这样:
desc "Deploy a new beta build to Google Play"
lane :beta do
build_number = number_of_commits()
Dir.chdir "../.." do
sh("flutter", "packages", "get")
sh("flutter", "clean")
sh("flutter", "build", "appbundle", "--build-number=#{build_number}")
end
upload_to_play_store(track: 'beta', aab: '../build/app/outputs/bundle/release/app.aab')
end
继续保存文件,然后运行fastlane beta
。它将逐步运行,为您构建应用程序并推送应用程序。
现在,我们将对 iOS 做同样的事情,但是将一些命令替换为它们各自的 iOS 命令。这应该在ios/Fastlane
目录中完成。
desc "Deploy a new build to Testflight"
lane :beta do
Dir.chdir "../.." do
sh("flutter", "packages", "get")
sh("flutter", "clean")
sh("flutter", "build", "ios", "--release", "--no-codesign")
end
build_ios_app(scheme: "MyApp")
upload_to_testflight
end
注:app 是两次搭建。第一个构建基于最新的 Flutter 工具链,而第二个构建构建将上传到 Testflight 的实际的.ipa
文件。
现在,有了 CircleCI
现在我们已经准备好了一切,是时候编写 CircleCI 配置了,这样分支的推送就可以转化为新的部署。
ios
对于 iOS 的部署,CircleCI 已经有相关文档了!设置带颤振的浪子展开的步骤类似于此处和此处和概述的步骤。
机器人
谈到要选择的 Docker 图像,有两个选项。你可以构建并推送 Flutter 项目使用的 Docker 镜像,在这里找到,或者你可以拉gmemstr/flutter-fastlane-android:29.0
,它构建在一个现有的 CircleCI Android Docker 镜像之上并安装 Flutter 和浪子,避免在运行时安装它的额外开销。
还要确保前面提到的环境变量被添加到您的项目中。即:
PLAY_STORE_UPLOAD_KEY
-base64 编码的key.jks
文件PLAY_STORE_UPLOAD_KEY_INFO
-base64 编码的文件,包含密码和其他关于上传签名密钥的信息SUPPLY_JSON_KEY_DATA
-您的 Google 服务帐户用于验证的 JSON 字符串
在您的项目根目录中,添加一个.circleci
文件夹,并在该文件夹中添加一个circleci.yml
文件。将以下配置添加到新创建的文件中:
version: 2.1
executors:
android-flutter:
docker:
- image: gmemstr/flutter-fastlane-android:29.0
environment:
TERM: dumb
_JAVA_OPTIONS: "-Xmx2048m -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap"
GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx2048m"'
上面的代码片段定义了一个执行器,由于 CircleCI 2.1 中使用了可重用配置和 orbs ,我们可以在以后的配置中重用这个执行器。它还包括一些环境变量,以确保 Java 在构建应用程序时不会消耗我们所有的内存。接下来,我们将定义希望运行命令的作业。
jobs:
beta_deploy:
executor: android-flutter
steps:
- checkout
- run: echo "$PLAY_STORE_UPLOAD_KEY" | base64 --decode > key.jks
- run: echo "$PLAY_STORE_UPLOAD_KEY_INFO" | base64 --decode > android/key.properties
- run: cd android && fastlane beta
最后,我们将定义我们的工作流,它将只在新代码被推送到beta
分支时运行作业。
workflows:
deploy:
jobs:
- beta_deploy:
filters:
branches:
only: beta
最终,您的配置将如下所示:
version: 2.1
executors:
android-flutter:
docker:
- image: gmemstr/flutter-fastlane:latest
environment:
TERM: dumb
_JAVA_OPTIONS: "-Xmx2048m -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap"
GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx2048m"'
jobs:
beta_deploy:
executor: android-flutter
steps:
- checkout
- run: echo "$PLAY_STORE_UPLOAD_KEY" | base64 --decode > key.jks
- run: echo "$PLAY_STORE_UPLOAD_KEY_INFO" | base64 --decode > android/key.properties
- run: cd android && fastlane beta
workflows:
deploy:
jobs:
- beta_deploy:
filters:
branches:
only: beta
在 CircleCI 上设置您的项目。一旦你点击设置项目,你将被带到一个文本编辑器,允许你从上面复制配置。点击开始建造。现在,对 beta 分支的每个新提交都将导致部署。
将 Laravel 应用程序部署到 Heroku | CircleCI
本教程涵盖:
- 克隆 Laravel 应用程序并在本地运行它
- 在 Heroku 上创建一个应用程序,包括 ClearDB MySQL 插件
- 为将 Laravel 应用程序部署到 Heroku 创建管道配置
在本教程中,我将向您展示如何建立一个连续部署管道,以最少的麻烦将 Laravel 应用程序部署到 Heroku 平台。自动化部署有助于团队限制部署过程中的人工干预,降低错误风险,并简化整个软件发布过程。
先决条件
对于这篇文章,你需要:
我们的教程是平台无关的,但是使用 CircleCI 作为例子。如果你没有 CircleCI 账号,请在 注册一个免费的 。
入门指南
首先,克隆一个用 Laravel 构建的作者应用程序。使用这个应用程序,您可以通过陈述作者的name
、email
、github
用户名和location
来创建一个作者列表。从终端输入以下命令下载项目:
git clone --single-branch --branch template https://github.com/CIRCLECI-GWP/laravel-heroku-app.git laravel-heroku-app
进入应用程序,安装其依赖项并生成应用程序密钥:
cd laravel-heroku-app
composer install
接下来,创建一个.env
文件,并使用以下命令生成应用程序密钥:
cp .env.example .env
php artisan key:generate
在本地运行应用程序
在本地运行应用程序可以确认它是否按预期工作。首先,更新数据库凭证:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=YOUR_DATABASE_NAME
DB_USERNAME=YOUR_DATABASE_USERNAME
DB_PASSWORD=YOUR_DATABASE_PASSWORD
用您计划使用的值替换YOUR_DATABASE_NAME
、YOUR_DATABASE_USERNAME
和YOUR_DATABASE_PASSWORD
。
接下来,创建数据库表并运行应用程序:
php artisan migrate
php artisan serve
进入http://localhost:8000
查看应用主页。
点击作者查看作者列表。如果没有创建作者,列标签下面的空间将是空白的。
点击创建新作者添加新作者。
输入详细信息,点击提交。
既然您已经确认了演示应用程序可以工作,那么您就可以开始设置 Heroku 的部署了。
在 Heroku 上创建应用程序
要在 Heroku 上创建应用程序,请转到 Heroku 仪表板。点击新增,然后点击新增 App 。在表单中填写您的应用程序和您所在地区的名称。
然后,点击创建 app 。您将被重定向到新创建的应用程序的部署视图。
添加 ClearDB MySQL 附加组件
默认情况下, Laravel 为五个数据库提供第一方支持。为了保持一致性,最好在 Heroku 上维护与本地相同的 MySQL 数据库。Heroku 默认使用 PostgreSQL,但是因为这个教程项目使用 MySQL,所以您需要安装一个名为 ClearDB 的 MySQL 附加组件。对于本教程来说,免费计划应该足够好。
要安装 ClearDB,点击 Resources,搜索 ClearDB,并选择它。
选择免费计划,然后点击提交订单。
一旦该过程完成,ClearDB 将生成一个连接字符串,并将其包含在应用程序的配置变量中。
要更新应用程序的其他环境变量,点击设置,然后点击显示配置变量。复制CLEARDB_DATABASE_URL
并粘贴到您可以轻松提取凭证的地方。
数据库 URL 应该是这样的格式:mysql://YOUR_DB_USERNAME:YOUR_DB_PASSWORD@YOUR_DB_HOST/YOUR_DB_NAME?reconnect=true
。使用生成的数据库 URL,添加以下变量:
APP_DEBUG
打开和关闭 Laravel 应用程序的调试模式。APP_ENV
表示应用程序是本地的还是生产中的。APP_KEY
是生成的应用密钥。您可以使用本地机器上的副本。APP_NAME
指定应用程序名称。APP_URL
用于说明您的应用程序的 URL。在本例中,它是我们的 Heroku 应用程序的 URL。
现在您需要一个 API 密钥。您将使用此密钥和应用程序名称将您的 CircleCI 管道连接到 Heroku。要获取您的 API 密钥,请打开帐户设置页面。滚动到 API 键部分。
点击显示按钮,复制 API 密钥。将它保存在您以后可以轻松找到的地方。
添加 CircleCI 配置文件
在本部分教程中,我将指导您为 CircleCI 添加管道配置。对于这个项目,管道由将我们的应用程序部署到 Heroku 的步骤组成。
在项目的根目录下,创建一个名为.circleci
的文件夹。在该文件夹中,创建一个名为config.yml
的文件。在新创建的文件中,添加以下配置:
version: 2.1
orbs:
heroku: circleci/heroku@1.2.6
jobs:
build:
docker:
- image: cimg/php:8.0
steps:
- checkout
# Download and cache dependencies
- restore_cache:
keys:
- v1-dependencies-{{ checksum "composer.json" }}
- run:
name: "Install Dependencies"
command: composer install -n --prefer-dist
- save_cache:
key: v1-dependencies-{{ checksum "composer.json" }}
paths:
- ./vendor
deploy_app:
executor: heroku/default
steps:
- checkout
- heroku/install
- heroku/deploy-via-git:
force: true
- run:
command: |
heroku run --app=${HEROKU_APP_NAME} php artisan migrate --force
workflows:
deploy:
jobs:
- build
- deploy_app
这个配置文件为项目指定了 CircleCI 的版本。在撰写本文时,orbs
键调用最新版本的 Heroku orb 。这个 orb 抽象了设置 Heroku CLI 时通常涉及的复杂性。orb 会自动安装它,并使用它将应用程序部署到 Heroku。
build
任务从 CircleCI Docker Hub 注册中心获取 PHP Docker 图像。您的代码从存储库中签出,并且安装了项目的依赖项。如果为您的项目配置了测试,这将是运行测试的好地方。我们将跳过本教程的测试,只关注 Heroku 平台的部署。
deploy_app
作业使用heroku/default
执行器来检查项目并安装 Heroku CLI。部署应用程序并运行迁移命令,以便在 Heroku 上为您的应用程序创建数据库。
注意: 仅运行一次迁移命令(在第一次部署时)。然后编辑配置文件以删除 migrate 命令。
创建配置文件
Procfile 帮助定义启动应用程序时应该执行的过程类型和命令。对于 PHP 运行时,您可以选择使用 Apache2 或 Nginx 作为 web 服务器来运行这个应用程序。对于本教程,我们将使用 Apache2 来服务我们的应用程序。要设置它,导航到您的项目的根目录,创建一个名为Procfile
的新文件,并用以下内容填充它:
web: vendor/bin/heroku-php-apache2 public/
这个命令将 web 服务器设置为 Apache,并指定应用程序的服务文件夹。对于这个项目,它是public
文件夹。
接下来,在 GitHub 上建立一个存储库,并将项目链接到 CircleCI。查看将您的项目推送到 GitHub 以获得逐步说明。
登录您的 CircleCI 帐户。如果你注册了你的 GitHub 账户,你所有的库都可以在你项目的仪表盘上看到。
点击为您的laravel-heroku-app
项目设置项目。
系统将提示您编写新的配置文件,或者在项目中使用现有的配置文件。选择现有选项。在 GitHub 上输入您的代码所在的分支的名称,然后点击 Let's Go 按钮。
您的第一个工作流将开始运行,但会失败。
此部署过程失败,因为您尚未提供 Heroku API 密钥。你现在可以弥补了。点击项目设置按钮,然后点击环境变量。添加这两个新变量:
HEROKU_APP_NAME
是 Heroku 中的 app 名称(laravel-heroku-application
)。HEROKU_API_KEY
是您从帐户设置页面获取的 Heroku API 密钥。
从失败的中选择重新运行工作流以重新运行 Heroku 部署。这一次,您的工作流将成功运行。
您可以从应用的迁移中确认这一点。
要确认工作流成功,请在浏览器中打开新部署的应用程序。您的应用程序的 URL 应该是这样的格式https://<HEROKU_APP_NAME>.herokuapp.com/
结论
在本教程中,您已经学习了使用 CircleCI 和 Heroku 为 Laravel 应用程序设置连续部署管道所需的步骤和过程。使用这个管道可以确保特性部署的质量,并大大降低影响生产环境的人为错误的风险。
我希望本教程对你有所帮助。点击 GitHub 查看这里构建的项目的完整源代码。下次见,好好享受吧!
Oluyemi 是一名拥有电信工程背景的技术爱好者。出于对解决用户日常遇到的问题的浓厚兴趣,他冒险进入编程领域,并从那时起将他解决问题的技能用于构建 web 和移动软件。Oluyemi 是一名热衷于分享知识的全栈软件工程师,他在世界各地的几个博客上发表了大量技术文章和博客文章。由于精通技术,他的爱好包括尝试新的编程语言和框架。
Oluyemi 是一名拥有电信工程背景的技术爱好者。出于对解决用户日常遇到的问题的浓厚兴趣,他冒险进入编程领域,并从那时起将他的问题解决技能用于构建 web 和移动软件。Oluyemi 是一名热衷于分享知识的全栈软件工程师,他在世界各地的几个博客上发表了大量技术文章和博客文章。作为技术专家,他的爱好包括尝试新的编程语言和框架。
在 Netlify | CircleCI 中构建并部署一个 Nuxt3 应用程序
本教程涵盖:
- 构建 Nuxt3 应用程序
- 为应用程序编写自动化测试
- 将应用部署到 Netlify
假设您想在 Netlify 上构建和部署一个 Nuxt3 应用程序。因为 Netlify 上不允许自定义脚本,所以在将网站部署到 Jamstack 托管平台之前,您将无法执行自动化测试等自定义任务。这就是持续集成/持续部署发挥作用的地方。使用 CI/CD 系统,您可以运行创建成功部署的自动化测试。在本教程中,我将带领您构建一个 Nuxt3 应用程序,为它编写自动化测试,并在 Netlify 上部署它。
Nuxt.js 是什么?
Nuxt.js 是一个元框架,用于构建通用应用程序,或者运行在客户端和服务器端的应用程序。它是一个基于 Vue.js 构建的免费开源 JavaScript 库。Nuxt.js 的想法来自于 Next.js ,它为 React.js 生态系统提供了类似的目的。
什么是 Netlify?
Netlify 是开发团队托管 Jamstack 网站的热门选择。它允许您只需点击几下鼠标,即可连接您的存储库并部署您的静态网站。有时你有一个复杂的构建步骤,你需要对它进行一些控制。
先决条件
要完成本教程,您需要:
我们的教程是平台无关的,但是使用 CircleCI 作为例子。如果你没有 CircleCI 账号,请在 注册一个免费的 。
设置 Nuxt3 应用程序
第一步是设置一个要部署到 Netlify 的 Nuxt3 应用程序。
打开您的终端,导航到您想要的路径,并运行以下命令:
npx nuxi init nuxt3-app
接下来,导航到nuxt3-app
目录,通过运行以下命令安装 NPM 依赖项:
cd nuxt3-app
npm install
安装完依赖项后,通过运行以下命令启动 Nuxt3 开发服务器:
npm run dev -- -o
使用浏览器访问http://localhost:3000
,它显示了一个新的 Nuxt3 应用程序的默认主页。
在 Nuxt3 应用程序中添加页面
要使您的网站更具互动性,您可以向其中添加页面。
在项目的根目录下创建一个pages
目录。在pages
目录中,创建一个index.vue
文件并添加以下代码:
<template>
<div>
<h1>Home</h1>
<p>This is Home page</p>
<nuxt-link to="/about">Go to About</nuxt-link>
</div>
</template>
接下来,在pages
目录中,创建一个about.vue
文件,并将以下代码添加到其中:
<template>
<div>
<h1>About</h1>
<p>This is About page</p>
<nuxt-link to="/">Go to Home</nuxt-link>
</div>
</template>
最后,保存你的进度,在浏览器上访问 Nuxt3 应用。
安装 Netlify CLI
Netlify 命令行界面(CLI) 允许您通过在 CI/CD 系统定制版本中运行命令行脚本,将您的网站部署到 Netlify。您需要将 CLI 作为开发依赖项安装到您的项目中。
转到项目的根目录,在终端中运行以下命令:
npm install --save-dev netlify-cli
一旦安装完成,将项目代码推送到 GitHub 。
设置网络生活
首先,访问 Netlify 的仪表板,点击添加新站点 > 导入一个现有项目。
接下来,选择 GitHub 作为您的提供商,并搜索您的 GitHub 存储库。如果你的项目没有出现在列表中,点击在 GitHub 上配置 Netlify 应用程序并授权 Netlify 访问你的库。
接下来,快速回顾一下您的 Netlify 项目的基本构建设置。如果一切正常,点击部署站点允许 Netlify 首次部署您的 Nuxt3 应用。
构建过程完成后,请访问应用仪表板上的部署 URL。在我们这里是https://aquamarine-bublanina-66d811.netlify.app/
。
最后,当从 CircleCI 部署到 Netlify 时,您将需要一个站点 ID 和一个个人访问令牌:
-
对于
SITE ID
,请使用您网站的应用 ID。点击站点设置选项卡,然后点击常规 > 站点详情即可找到。 -
点击用户设置,然后点击应用,即可获得
Personal Access token
。将您的访问令牌保存在安全的地方;您将无法再次显示它。
停止网络构建
有了这个设置,无论何时按下main_ branch
按钮,都会触发两次部署。一个部署在 Netlify,另一个部署在 CircleCI。为了节省资源,您只想从单一来源进行部署;在这种情况下,CircleCI。这意味着您需要禁用 Netlify 上的构建。
在 Netlify 仪表板上返回到您站点的页面。点击站点设置选项卡。在侧面菜单栏上点击构建&部署,然后点击编辑设置,选择停止构建。完成后保存您的更改。
就是这样。现在 Netlify 不会在你推进到你的主分支时触发项目部署。
设置 CircleCI
现在 Netlify 设置完成了,您可以开始设置 CircleCI 了。
在项目的根目录下,创建一个.circleci
目录,并向其中添加一个config.yml
文件。在这里,您将使用 CircleCI 编写构建和部署您的网站到 Netlify 的配置。现在,打开新创建的文件并添加以下内容:
version: 2.1
jobs:
build:
working_directory: ~/repo
docker:
- image: cimg/node:14.19.0
steps:
- checkout
- run:
name: Update NPM
command: "sudo npm install -g npm"
- restore_cache:
key: dependency-cache-{{ checksum "package-lock.json" }}
- run:
name: Install Dependencies
command: npm install
- save_cache:
key: dependency-cache-{{ checksum "package-lock.json" }}
paths:
- ./node_modules
- run:
name: Nuxt3 Build
command: npm run generate
- save_cache:
key: nuxt3-public-cache-{{ .Branch }}
paths:
- ./.output/public
workflows:
build-deploy:
jobs:
- build:
filters:
branches:
only:
- main
这种配置:
- 从存储库中检出项目
- 安装并缓存项目依赖项
- 构建(
npm run generate
)并缓存.output/public
目录,该目录保存 Nuxt3 网站的生产构建 - 将工作流配置为仅在推送至主分支时运行
接下来,将这些新的变更推送到您的 GitHub 存储库中。
现在,在 CircleCI 仪表板上,从左侧边栏菜单中点击项目。
从项目列表中,找到您的项目并点击设置项目。您将收到 CircleCI 自动检测您的配置文件的通知。快速浏览一下,点击设置项目。
这将在 CircleCI 上成功触发构建,但不会部署到 Netlify。这是因为您尚未添加凭据。接下来你会这么做。
接下来,点击项目设置。在项目设置页面,点击左侧工具条菜单中的环境变量。在此页面上,添加这两个环境变量:
NETLIFY_SITE_ID
是您的 Netlify 应用程序的应用程序 ID。NETLIFY_ACCESS_TOKEN
是您的网络个人访问令牌。
更新 CircleCI 配置文件
现在您已经在 CircleCI 上设置了项目,您可以使用部署凭证更新配置文件,并使用 Netlify CLI 部署您的网站。
更新config.yml
文件的内容,如下所示:
version: 2.1
jobs:
build:
working_directory: ~/repo
docker:
- image: cimg/node:14.19.0
steps:
# 1
- checkout
- run:
name: Update NPM
command: "sudo npm install -g npm"
- restore_cache:
key: dependency-cache-{{ checksum "package-lock.json" }}
# 2
- run:
name: Install Dependencies
command: npm install
- save_cache:
key: dependency-cache-{{ checksum "package-lock.json" }}
paths:
- ./node_modules
# 3
- run:
name: Nuxt3 Build
command: npm run generate
- save_cache:
key: nuxt3-public-cache-{{ .Branch }}
paths:
- ./.output/public
# 4
- run:
name: Deploy to Netlify
command: ./node_modules/.bin/netlify deploy --site $NETLIFY_SITE_ID --auth $NETLIFY_ACCESS_TOKEN --prod --dir=./.output/public
# 5
workflows:
version: 2
build-deploy:
jobs:
- build:
filters:
branches:
only:
- main
此更新添加了脚本,以便使用您之前创建的凭据直接部署到 Netlify。
接下来,对您的代码进行一些修改,以验证新网站确实是从 CircleCI 部署的,并且将您的修改推送到 GitHub 。此按钮将触发部署管道,并将您的网站部署到 Netlify。
构建成功后,再次访问您的网站以验证您部署的更改。
您可能希望访问 Netlify 仪表板,以验证 Netlify 上没有触发任何构建。
结论
在本文中,您学习了使用 CircleCI 在 Netlify 上构建和部署 Nuxt3 应用程序。这个 CI/CD 系统允许您运行定制脚本,这些脚本有时会在 Netlify 等托管平台上被阻止。接下来,您可以使用 CircleCI webhooks 从您的 CMS 触发部署。
如果你使用 Heroku 作为你的托管平台,你可以阅读我们关于使用 CircleCI 管道定制部署到 Heroku 的教程。
自动将私有 Docker 映像部署到 Amazon ECR - CircleCI
原文:https://circleci.com/blog/deploy-private-docker-image-amazon-ecr/
本文介绍了如何使用 CircleCI orbs 构建生产级 Docker 映像并将其推送到 Amazon 弹性容器注册中心(ECR)进行存储。
什么是亚马逊 ECR?
亚马逊 ECR 是一个完全托管的私有 Docker 容器注册中心,开发者可以很容易地存储、管理和部署 Docker 容器映像。亚马逊 ECR 与亚马逊弹性容器服务亚马逊 ECSe 和亚马逊弹性 Kubernetes 服务亚马逊 EKS 无缝集成。亚马逊 ECR 也可以和其他云厂商一起使用。
为什么要使用像 Amazon ECR 这样的私有 Docker 注册中心?
- 在许多情况下,分离开发、测试和生产注册是可取的。
- 它是完全托管的,因此无需运营自己的容器存储库或担心底层基础架构的扩展。
- 很安全。具有扫描功能和基于角色的访问控制的私有容器注册表提供了更多的安全性、治理(IAM)和高效管理。它通过 HTTPS 传输您的容器图像,并自动加密您的静态图像。
- 在运行容器的系统附近运行注册中心可以减少部署延迟并减少网络中断的风险。
开发人员需要使用注册表来存储应用程序开发过程中创建的图像。持续集成管道连接构建容器图像,并将这些工件推入亚马逊 ECR。想象一个管道,其中您推送一个 commit,该 commit 触发 CircleCI 上的一个构建,该构建将一个新图像推送到 Amazon ECR 中。然后,您的注册中心可以启动 webhook 并触发部署。所有这些都不需要人工做任何事情。注册中心使得这种完全自动化的管道更加容易。放在注册表中的容器映像可以在开发的不同阶段使用。在几个步骤中,使用 CircleCI orbs ,我们将封装一个简单的 Node.js 应用程序,构建映像,并将其推送到 Amazon ECR。
设置 Amazon ECR
从 AWS 管理控制台中,选择 IAM。此服务允许您管理对 AWS 资源的访问。
创建角色/用户。我把我的名字叫做ci-cd-ecr
,但是任何名字都可以。确保您选择了访问键-编程访问选项。
接下来,为用户设置权限。点击直接附加已有保单。这个截屏显示了在 AWS 上成功地为您的图像创建一个私有存储库并拥有其他修改的完全访问权限所需的内容。
点击下一个两次,创建新用户。
您将收到一条成功消息以及您的用户凭据。该页面只显示一次,因此请记下访问密钥 ID 和秘密访问密钥,稍后将会用到。或者,您可以下载提供的包含相同凭据的 csv 文件。
使用 AWS-ECR orb 设置 CircleCI 管道
这个演示的代码可以在 GitHub 这里找到。使用以下命令克隆应用程序:
git clone https://github.com/CIRCLECI-GWP/circleci-ecr-demo
在.circleci/
文件夹中找到 CircleCI 配置文件。使用 orbs,正如您将看到的,您可以构建一个映像并将其推送到 Amazon ECR,只需 13 行配置!aws-ecr orb 预装了以下命令:
- 建立形象
- 登录亚马逊 ECR
- 创建一个 Amazon ECR repo(如果不存在)
- 将图片推送到亚马逊 ECR
以下是您的管道的完整配置:
version: 2.1
orbs:
aws-ecr: circleci/aws-ecr@8.1.3
workflows:
build_and_push_image:
jobs:
- aws-ecr/build-and-push-image:
context: aws-dev
create-repo: true
dockerfile: Dockerfile
path: .
repo: circleci-ecr-demo
tag: "$CIRCLE_SHA1"
这个配置文件使用 Amazon 弹性容器注册中心 orb 来构建和部署 Docker 映像。dockerfile:
命令指定 docker 文件的路径。演示报告使用以下 Dockerfile 文件:
# Set the base image to use for subsequent instructions
FROM node:alpine
# Add metadata to an image
LABEL app="simple-node-application"
# Directive to set environmental variables key to value pair
ENV NPM_CONFIG_LOGLEVEL warn
# Set the working directory for any subsequent ADD, COPY, CMD, ENTRYPOINT,
# or RUN instructions that follow it in the Dockerfile
WORKDIR /usr/src/app
# Copy files or folders from source to the dest path in the image's filesystem.
COPY package.json /usr/src/app/
COPY . /usr/src/app/
# Execute any commands on top of the current image as a new layer and commit the results.
RUN npm install --production
# Define the network ports that this container will listen on at runtime.
EXPOSE 3000
# Configure the container to be run as an executable.
ENTRYPOINT ["npm", "start"]
为 Amazon ECR 添加上下文和设置环境变量
在您的 CircleCI 仪表板中,通过单击侧边栏中的链接进入组织设置页面。接下来,选择上下文。点击创建上下文按钮,为您的上下文添加一个唯一的名称。该上下文出现在安全性设置为All members
的列表中,表示组织中的任何人都可以在运行时访问该上下文。正如本教程的.circleci/config.yml
配置中所指定的,上下文名称应该是aws-dev
。
接下来,选择 aws-credentials 上下文。
点击添加环境变量按钮。输入要与此上下文关联的变量名和值。点击添加变量按钮保存。aws-dev
上下文需要这三个环境变量:
AWS_ACCESS_KEY_ID
是您之前创建的ci-cd-ecr
IAM 角色的 AWS 访问键 id。AWS_SECRET_ACCESS_KEY
是您之前创建的ci-cd-ecr
IAM 角色的 AWS 密钥。AWS_ECR_REGISTRY_ID
是与 ECR 账户相关的 12 位 AWS id。这也称为帐户 ID。AWS_REGION
是您的 ECR 资源所在的 AWS 区域。
注意: 你不必设置$CIRCLE_SHA1
,因为它是所有 CircleCI 项目中可用的默认变量。这是当前构建的最后一次提交的SHA1
散列。使用 Git 提交散列让您能够跟踪容器中的内容。理想情况下,它允许您将容器追溯到其 Docker 映像,然后追溯到映像中包含的 Docker 文件和代码。在自动化执行环境中,这将带您回到导致 Docker 映像构建的提交。
将应用程序连接到 CircleCI
下一步是在 GitHub 上建立一个资源库,并将项目链接到 CircleCI。查看将项目推送到 GitHub 以获取指示。
登录您的 CircleCI 帐户。如果你注册了你的 GitHub 账户,你所有的库都可以在你项目的仪表盘上看到。找到您的项目(本例中为circleci-ecr-demo
)并点击设置项目。
在 GitHub 上输入您的代码所在的分支的名称,然后点击设置项目。
您的第一个工作流将开始运行并成功完成。
要查看存储库信息,请转到您的 AWS 管理控制台。
结论
CircleCI 和 Amazon ECR 都成功配置后,您就可以开始构建映像并将它们推送到存储库了。
只需几行代码,您就可以构建 Docker 图像并将其推送到 Amazon ECR。CircleCI orbs 通过将预构建的命令、作业和执行器导入 CircleCI 配置文件来节省时间,提供了与云服务和其他工具的轻松集成。
Dominic Motuka 是 Andela 的 DevOps 工程师,在 AWS 和 GCP 支持、自动化和优化生产就绪部署方面拥有 4 年多的实践经验,利用配置管理、CI/CD 和 DevOps 流程。
将 React 应用程序自动部署到 Firebase | CircleCI
本教程涵盖:
- 构建一个示例 React 应用程序
- 在 Firebase 上设置和配置应用程序
- 创建连续部署管道
许多平台为 React 和其他 JavaScript 框架提供免费的托管服务。这些框架可用于构建单页面应用程序,这在您需要发布最小可行产品或快速概念验证时非常方便。您的开发伙伴正在利用这些工具,您也可以。为了缩小选择范围,我将在本教程中重点介绍 Firebase。
Firebase 是 Google 开发的一个开发平台,提供文件存储、托管、数据库、认证和分析。Firebase 是免费的,默认提供 SSL 证书,并在多个地区提供令人印象深刻的速度。
在本教程中,您将学习如何通过使用 CircleCI 设置连续部署管道,在 Firebase 上托管 React 应用程序。
先决条件
对于本教程,您需要:
我们的教程是平台无关的,但是使用 CircleCI 作为例子。如果你没有 CircleCI 账号,请在 注册一个免费的 。
克隆演示项目
首先,在 GitHub 上克隆本教程的演示项目。使用 Git 发出以下命令:
git clone https://github.com/yemiwebby/react-app-firebase.git
这个演示应用程序从测试用的免费 Rest API 中检索虚拟用户列表。
接下来,进入新克隆的应用程序,安装其依赖项,并使用以下命令运行应用程序:
// change directory
cd react-app-firebase
// install dependencies
npm install
// Run the application
npm run start
前往http://localhost:3000
查看本地主页。
现在您已经知道演示应用程序正在工作,您已经准备好在 Firebase 上建立一个项目了。
在 Firebase 上建立一个项目
你需要一个免费帐户来访问 Firebase 提供的所有功能,所以打开一个 Firebase 帐户并进入 Firebase 控制台页面。
接下来,使用以下步骤:
- 点击添加项目按钮。
- 输入项目的名称。我给我的取名为
react-app-firebase
。请记住,项目 id 在 Firebase 中是唯一的。 - 点击继续。
- 禁用谷歌分析;这个项目不需要它。
- 再次点击继续。
您已经成功地在 Firebase 上创建了一个项目。
配置 Firebase 托管
为了在 Firebase 上成功地托管您的应用程序,您需要安装它的工具,并在您的项目中初始化它。
打开新的终端。运行以下命令以全局安装 Firebase 工具:
npm install -g firebase-tools
安装完成后,您现在可以全局访问 Firebase 命令行界面工具。您可以使用它们将代码和资产部署到新创建的 Firebase 项目中。
将 React 连接到 Firebase
从终端登录到您的 Firebase 帐户:
firebase login
该命令将打开一个浏览器,并提示您选择一个帐户。
接下来,确保您在react-app-firebase
项目的根目录下,并发出以下命令来初始化它:
firebase init
系统会提示您回答一些问题。
- 选择托管:为 Firebase 托管配置文件,并(可选)设置 GitHub 操作部署。
- 使用现有项目:选择您之前创建的 Firebase 项目(
react-app-firebase
)。 - 输入
build
作为公共目录。 - 配置为单页 app:
Yes
。 - 使用 GitHub 设置自动构建和部署:
No
。对于本教程,我们使用 CircleCI 来运行测试和处理部署。
以下是终端的输出:
######## #### ######## ######## ######## ### ###### ########
## ## ## ## ## ## ## ## ## ## ##
###### ## ######## ###### ######## ######### ###### ######
## ## ## ## ## ## ## ## ## ## ##
## #### ## ## ######## ######## ## ## ###### ########
You are about to initialize a Firebase project in this directory:
/Users/yemiwebby/tutorial/circleci/react-app-firebase
? Which Firebase features do you want to set up for this directory? Press Space to select features, th
en Enter to confirm your choices. Hosting: Configure files for Firebase Hosting and (optionally) set u
p GitHub Action deploys, Hosting: Set up GitHub Action deploys
=== Project Setup
First, lets associate this project directory with a Firebase project.
You can create multiple project aliases by running firebase use --add,
but for now we will just set up a default project.
? Please select an option: Use an existing project
? Select a default Firebase project for this directory: react-app-firebase-52972 (react-app-firebase)
i Using project react-app-firebase-52972 (react-app-firebase)
=== Hosting Setup
Your public directory is the folder (relative to your project directory) that
will contain Hosting assets to be uploaded with firebase deploy. If you
have a build process for your assets, use your builds output directory.
? What do you want to use as your public directory? build
? Configure as a single-page app (rewrite all urls to /index.html)? Yes
? Set up automatic builds and deploys with GitHub? No
✔ Wrote build/index.html
i Writing configuration info to firebase.json...
i Writing project information to .firebaserc...
✔ Firebase initialization complete!
项目的初始化过程还在项目的根目录下生成了两个唯一的文件。这些文件是成功部署所必需的,并且必须签入源代码管理。
firebase.json
包含您项目的托管配置。它指示 Firebase CLI 上传和部署项目目录中的文件。.firebaserc
指定成功部署到 Firebase 后,连接到上传代码的项目。
配置 CircleCI
克隆的项目中已经存在配置文件。转到.circleci/config.yml
。打开它,确保它与以下内容匹配:
version: 2.1
jobs:
build:
working_directory: ~/project
docker:
- image: cimg/node:17.4.0
steps:
- checkout
- run:
name: Update NPM
command: "sudo npm install -g npm"
- restore_cache:
key: dependency-cache-{{ checksum "package-lock.json" }}
- run:
name: Install Dependencies
command: npm install
- run: npm install --save-dev firebase-tools
- save_cache:
key: dependency-cache-{{ checksum "package-lock.json" }}
paths:
- ./node_modules
- run:
name: Build application for production
command: npm run build
- run:
name: Deploy app to Firebase
command: ./node_modules/.bin/firebase deploy --token=$FIREBASE_TOKEN
workflows:
build-and-deploy:
jobs:
- build
这个配置指定了在 CircleCI 上安装和构建 React 应用程序所需的所有工具。它用npm install --save-dev firebase-tools
安装了 Firebase 工具,并设置了一个命令,一旦测试成功,就自动将应用程序部署到 Firebase。
部署将需要FIREBASE_TOKEN
。您是从终端登录的,因此可以使用 Firebase CLI 轻松创建令牌。输入以下命令:
firebase login:ci
这将打开一个浏览器,您可以在其中验证您的帐户。然后,令牌会打印在您的终端上。
把这个复制下来,保存在方便的地方。在本教程的后面部分,您将需要它。
下一步是在 GitHub 上建立一个资源库,并将项目链接到 CircleCI。查看将项目推送到 GitHub 以获取指示。
一旦你的 GitHub 库被更新,登录到你的 CircleCI 账户。如果你注册了你的 GitHub 账户,你所有的库都可以在你项目的仪表盘上看到。
接下来,找到你的react-app-firebase
项目,点击设置项目。
系统将提示您编写新的配置文件或使用现有的配置文件。选择现有的分支,并输入您的代码在 GitHub 上所在的分支的名称。点击设置项目。
您的第一个工作流将开始运行。但是构建将会失败,因为您还没有创建FIREBASE_TOKEN
环境变量。
要解决这个问题,您需要添加FIREBASE_TOKEN
作为环境变量。点击项目设置,然后点击左边栏的环境变量。创建此变量:
FIREBASE_TOKEN
是您之前从终端生成的令牌的值。
回到仪表板,单击从失败的重新运行工作流。这将触发工作流,该工作流现在已成功构建。
转到上一步中显示的主机 URL。对我来说网址是:https://react-app-firebase-52972.web.app
。
结论
在本教程中,我们回顾了在 Firebase 上托管 React 应用程序的逐步过程。您下载了一个现有的 React 应用程序,并利用 CircleCI 基础设施来确保应用程序的部署不需要任何人工交互。
这里解释的过程适用于现有的和新的 React 应用程序。完整的源代码可以在 GitHub 的这里找到。
Oluyemi 是一名拥有电信工程背景的技术爱好者。出于对解决用户日常遇到的问题的浓厚兴趣,他冒险进入编程领域,并从那时起将他的问题解决技能用于构建 web 和移动软件。Oluyemi 是一名热衷于分享知识的全栈软件工程师,他在世界各地的几个博客上发表了大量技术文章和博客文章。作为技术专家,他的爱好包括尝试新的编程语言和框架。
使用 container runner | CircleCI 在 Kubernetes 中运行自托管 CI 作业
容器运行器,一个新的容器友好的自托管运行器,现在对所有 CircleCI 用户可用。对于有独特计算或安全需求的客户来说,自托管运行程序是一种受欢迎的解决方案。Container runner 降低了在容器化环境中使用自托管 runner 的门槛,并使中央 DevOps 团队能够更轻松地管理防火墙后的容器化 CI/CD 作业。
管理集装箱化的工作
CircleCI 的 Docker executor 允许您在持续集成工作流中充分利用容器化的速度和灵活性优势。在容器中运行作业是一种快速便捷的方式,可以确保您的构建可以访问所有必需的库和依赖项,而无需启动完整的机器环境所需的额外启动时间。
容器运行器消除了用户在他们的config.yml
文件中使用 Docker 语法。这意味着用户可以自由使用他们自己的自定义图像或 CircleCI 便利图像,并可以在作业执行期间轻松执行次级容器。
自动扩展基础设施
对于大多数开发团队来说,基础架构需求整天都在波动,维持固定水平的计算资源以适应峰值工作负载会很快导致云成本失控。为了应对这一挑战,拥有一个能够根据需求动态扩展和缩减基础架构的解决方案是很有帮助的。
Container runner 与 Kubernetes 集成,实现快速、轻松的容器编排。这意味着用户只需管理一个运行器代理,容器运行器将根据需要启动临时 pod 来执行并发 CI 作业。无论您需要同时运行 5 个作业还是 100 个作业,只需一个 container runner 实例就可以确保您拥有足够的基础设施。
在您的 Kubernetes 集群中安装容器运行器
安装您的第一个容器运行器只需要几个步骤,并且可以通过 CircleCI UI 轻松完成。只需在 CircleCI web 应用程序中创建一个 CircleCI 名称空间(如果您的组织还没有)和 runner 资源类,使用 Helm 在您的 Kubernetes 集群中安装容器运行器,并向您的 CircleCI config.yml
文件添加一个新作业,该作业使用 Docker 执行器和容器运行器的资源类。
下面是一个为build
作业使用容器运行器的配置示例:
version: 2.1
jobs:
build:
docker:
- image: cimg/base:2021.11
resource_class: <namespace>/<resource-class>
steps:
- checkout
- run: echo "Hi I'm on Runners!"
workflows:
build-workflow:
jobs:
- build
有关安装容器运行器和从 CircleCI 触发运行器作业的更多信息,请访问容器运行器安装文档。
结论
在防火墙后的容器化环境中运行 CI/CD 作业是许多软件团队日常开发工作的重要部分。在 CircleCI,我们相信支持团队是非常重要的,无论他们在哪里开发软件。无论您是在云中构建还是在自己的基础设施中构建,CircleCI 都能满足您的需求。
如果您有关于如何改善跑步者体验的想法,请访问 Canny 浏览或提交新想法。请访问我们的社区论坛讨论,让我们知道您是如何使用 runner 的。
最初的自托管运行程序 machine runner 主要用于虚拟和物理环境。集装箱转轮是机器转轮的补充,而不是替代。如需了解机器转轮的信息,请访问文档。
使用 Knative 和 ArgoCD | CircleCI 在 Kubernetes 上部署无服务器工作负载
原文:https://circleci.com/blog/deploy-serverless-workload-with-knative/
本教程涵盖:
- 设置 Knative 和 ArgoCD
- 监控和访问示例应用程序
- 创建一个管道,在 Kubernetes 集群上持续部署您的无服务器工作负载
容器和微服务彻底改变了应用程序在云上的部署方式。自 2014 年推出以来, Kubernetes 已经成为容器编排的标准工具。它提供了一组原语来运行弹性的分布式应用程序。
开发人员面临的一个主要困难是能够更多地关注代码的细节,而不是代码的基础设施。无服务器的计算方法是解决这个问题的有效方法。
无服务器允许通过抽象底层基础设施来运行事件驱动的功能。与传统的平台即服务(PaaS)相比,无服务器允许您的开发团队专注于服务的功能。基础设施问题,如扩展和容错,不再是一个障碍。
Knative 是一个开源的企业级解决方案,用于构建无服务器和事件驱动的应用程序。它的组件可以用来在 Kubernetes 上构建和部署无服务器应用程序。Knative 最初由 Google 开发,现在有来自 IBM、Red Hat 和 VMWare 的贡献者。
ArgoCD 是一个 Kubernetes-native 连续部署(CD)工具。它通过从 Git 存储库中提取代码更改,直接将代码更改部署到 Kubernetes 资源中。ArgoCD 遵循 GitOps 模式,不像某些外部 CD 解决方案那样只能支持基于推送的部署。该工具使开发人员能够从一个统一的平台控制应用程序更新和基础架构设置。
在本教程中,您将学习如何使用 CircleCI 和 ArgoCD 在 Azure Kubernetes 服务 (AKS)上使用 Knative 部署一个 Node.js 应用程序作为无服务器工作负载。您将使用 CircleCI orbs 创建一个持续集成管道,这些 orbs 是 YAML 配置的可重用包,将重复的配置片段压缩到一行代码中。当您在 GitHub 库中推送代码时,管道被触发。结果是一个自动管道,触发 ArgoCD 在 Kubernetes 集群上部署最新版本的应用程序。
先决条件
要完成本教程,您需要:
在你准备好这些东西之后,你就可以进入下一部分了。
克隆 Node.js 应用程序
在本教程中,我们主要关注在 Kubernetes 上部署应用程序。为了节省时间,您可以直接将 Node.js 应用程序克隆到您的 GitHub,并继续剩余的过程。
要克隆项目,请运行:
git clone https://github.com/CIRCLECI-GWP/nodejs-knative-argocd.git
该存储库中有两个分支:
main
分支只包含 Node.js 应用程序代码。circleci-project-setup
分支包含应用程序代码,以及您将在本教程中创建的所有 YAML 文件。
检查到main
分支。
Node.js 应用程序位于app.js
文件中:
const express = require("express");
const path = require("path");
const morgan = require("morgan");
const bodyParser = require("body-parser");
/* eslint-disable no-console */
const port = process.env.PORT || 1337;
const app = express();
app.use(morgan("dev"));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: "true" }));
app.use(bodyParser.json({ type: "application/vnd.api+json" }));
app.use(express.static(path.join(__dirname, "./")));
app.get("*", (req, res) => {
res.sendFile(path.join(__dirname, "./index.html"));
});
app.listen(port, (err) => {
if (err) {
console.log(err);
} else {
console.log(`App at: http://localhost:${port}`);
}
});
module.exports = app;
这段代码的关键是应用程序将要运行的port number
。这种情况下就是1337
。
通过首先安装依赖项,您可以在本地运行应用程序。在项目的根目录中,键入:
npm install
然后使用以下命令运行应用程序:
node app.js
应用程序现在应该在地址http://localhost:1337
启动并运行。
容器化 Node.js 应用程序
将应用程序部署到 Kubernetes 的第一步是将其容器化。使用 Docker 作为容器运行时工具的容器化应用程序要求您创建一个 Dockerfile 。Dockerfile 是一个文本文档,它包含用户可以在命令行上调用的所有命令来组合一个图像。
在项目的根目录下创建一个新文件,命名为Dockerfile
。将此内容复制到文件:
# Set the base image to use for subsequent instructions
FROM node:alpine
# Set the working directory for any subsequent ADD, COPY, CMD, ENTRYPOINT,
# or RUN instructions that follow it in the Dockerfile
WORKDIR /usr/src/app
# Copy files or folders from source to the dest path in the image's filesystem.
COPY package.json /usr/src/app/
COPY . /usr/src/app/
# Execute any commands on top of the current image as a new layer and commit the results.
RUN npm install --production
# Define the network ports that this container will listen to at runtime.
EXPOSE 1337
# Configure the container to be run as an executable.
ENTRYPOINT ["npm", "start"]
如果您已经安装了 Docker ,那么您可以在本地构建并运行容器进行测试。在本教程的后面,你将学习如何使用 CircleCI orbs 来自动化这个过程。
要构建和标记容器,您可以键入:
docker build -t nodejs-knative-argocd:latest .
通过从终端运行以下命令,确认映像已成功创建:
docker images
然后使用以下命令运行容器:
docker run -it -p 1337:1337 nodejs-knative-argocd:latest
应用程序现在应该在地址http://127.0.0.1:1337
启动并运行。
提交并推送对 GitHub 库的更改。
配置 Knative 服务清单
在 Knative 中,服务用于部署应用程序。要使用 Knative 创建应用程序,您必须创建一个定义服务的 YAML 文件。该 YAML 文件指定关于应用程序的元数据,指向应用程序的托管图像,并允许配置服务。
在项目的根目录下创建一个名为knative
的目录。然后,在新目录下创建一个新文件,并将其命名为service.yaml
。
service.yaml
的内容是:
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
creationTimestamp: null
name: nodejs-knative-argocd
spec:
template:
metadata:
creationTimestamp: null
name: nodejs-knative-argocd
spec:
containerConcurrency: 0
containers:
- image: docker.io/avik6028/nodejs-knative-argocd:latest
name: user-container
ports:
- containerPort: 1337
protocol: TCP
readinessProbe:
successThreshold: 1
tcpSocket:
port: 0
resources: {}
enableServiceLinks: false
timeoutSeconds: 300
status: {}
这个代码块的关键是spec.template.metadata.name
和spec.template.spec.containers[0].image
。它们表示模板和容器映像的名称,将使用 Knative 在 Kubernetes 集群上进行提取和部署。在持续集成过程中,这些值将使用最新的容器图像信息进行更新。
将这些文件提交并推入您之前克隆的 GitHub 存储库的main
分支。
启动 Azure Kubernetes 服务(AKS)群集
在本教程中,您将学习在 AKS 集群上部署应用程序。要创建 AKS 群集,您应该在计算机上安装 Microsoft Azure 帐户和 Azure CLI。将 CLI 连接到你的 Azure 账户。
现在,您可以在 Azure CLI 的帮助下启动 AKS 集群。
使用以下命令创建资源组:
az group create --name NodeRG --location eastus
启动双节点集群:
az aks create --resource-group NodeRG --name NodeCluster --node-count 2 --enable-addons http_application_routing
注意: 如果您之前在系统中生成了任何 SSH 密钥,您需要在命令中添加可选参数--generate-ssh-keys
。如果缺少 SSH 公钥和私钥文件,该参数将自动生成它们。密钥将存储在~/.ssh
目录中。
AKS 群集将需要 10 到 15 分钟才能启动。
在 Kubernetes 集群中安装 Knative
一旦集群启动并运行,您需要在集群内部安装 Knative,使用它来部署您的无服务器工作负载。
要安装该应用程序,请再次使用 Azure CLI。
使用以下命令配置kubectl
连接到 AKS:
az aks get-credentials --resource-group NodeRG --name NodeCluster
要安装 Knative 核心组件和自定义资源,请执行以下命令:
kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.7.1/serving-crds.yaml
kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.7.1/serving-core.yaml
Knative 还需要一个网络层来对外公开其服务。你需要安装 Kourier ,一个轻量级的 Knative 服务入口。
kubectl apply -f https://github.com/knative/net-kourier/releases/download/knative-v1.7.0/kourier.yaml
通过运行以下命令,将 Knative Serving 配置为默认使用 Kourier:
kubectl patch configmap/config-network \
--namespace knative-serving \
--type merge \
--patch '{"data":{"ingress-class":"kourier.ingress.networking.knative.dev"}}'
您可以配置 DNS,这样就不需要运行带有主机头的 curl 命令。Knative 提供了一个名为default-domain
的 Kubernetes 作业,该作业将 Knative 服务配置为使用sslip.io
作为默认 DNS 后缀。
kubectl apply -f https://github.com/knative/serving/releases/download/knative-v1.7.1/serving-default-domain.yaml
一旦执行了这些命令,Knative 将被安装在knative-serving
名称空间中。要将所有资源放入命名空间:
kubectl get all --namespace knative-serving
在 AKS 集群中安装 ArgoCD
一旦集群启动并运行,您需要在集群内部安装 ArgoCD,以使用它来部署您的应用程序。
要安装 ArgoCD,请输入:
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
当您执行这些命令时,argocd 将安装在“ArgoCD”命名空间中。要将所有资源放入命名空间:
kubectl get all --namespace argocd
公开 ArgoCD API 服务器
默认情况下,ArgoCD API 服务器不会向外部 IP 公开。因为在本教程中您将从 internet 访问应用程序,所以您需要通过服务类型负载平衡器向 ArgoCD 服务器提供外部 IP。
将 argocd-server 服务类型更改为 LoadBalancer:
kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "LoadBalancer"}}'
注意: 你也可以使用 Kubectl 端口转发来连接 API 服务器而不暴露服务。使用此命令:kubectl port-forward svc/argocd-server -n argocd 8080:443
您现在可以使用https://localhost:8080
访问 API 服务器。
访问 ArgoCD 门户网站
一旦使用外部 IP 公开了 ArgoCD API 服务器,就可以使用生成的外部 IP 地址访问门户。
因为您在argocd
名称空间中安装了 ArgoCD,所以使用这个命令来获取该名称空间的所有资源:
kubectl get all --namespace argocd
复制service/argocd-server
对应的External-IP
。
您可以在http://<EXTERNAL-IP>
访问应用程序。
我用了http://52.146.29.61/
。
要登录门户,您需要用户名和密码。用户名默认设置为admin
。
要获取密码,请执行以下命令:
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d; echo
使用此用户名和密码组合登录 ArgoCD 门户网站。
为 ArgoCD 配置 Kubernetes 清单
要配置 ArgoCD 在 Kubernetes 上部署您的应用程序,您必须设置 ArgoCD,使用 YAML 进行配置,以声明的方式连接 Git 存储库和 Kubernetes。
除此之外,您还可以从 Web 门户或使用 ArgoCD CLI 设置 ArgoCD。但是在本文中,我们试图遵循 GitOps 原则,Git 存储库应该作为唯一的事实来源,通过 YAML 文件的声明性方法效果最好。
ArgoCD 的关键特性和功能之一是通过手动或自动策略将应用程序部署到 Kubernetes 集群。
首先,在项目的根目录下创建一个名为argocd
的目录。在新目录下创建一个新文件,命名为config.yaml
。
手动同步策略
顾名思义,通过这个策略,您将能够通过 CI/CD 管道手动同步您的应用程序。无论何时进行代码更改,CI/CD 管道都会被触发,并调用 ArgoCD 服务器 API,根据您将提交的更改启动同步过程。要与 ArgoCD 服务器 API 通信,可以使用 ArgoCD CLI。您也可以使用适用于各种编程语言的 SDK 之一。
为 ArgoCD 设置手动同步策略,将其粘贴到config.yaml
:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: nodejs-knative-argocd
namespace: argocd
spec:
destination:
namespace: nodejs
server: 'https://kubernetes.default.svc'
source:
path: knative
repoURL: 'https://github.com/CIRCLECI-GWP/nodejs-knative-argocd'
targetRevision: circleci-project-setup
project: default
自动同步策略
ArgoCD 能够在检测到 Git 中所需清单与集群中实时状态之间的差异时,自动同步应用程序。
自动同步的一个好处是 CI/CD 管道不再需要直接访问 ArgoCD API 服务器来执行部署。取而代之的是,管道使用跟踪 Git repo 中的清单更改来提交和推送 Git 存储库。
如果您想设置为自动同步策略,您需要将其粘贴到config.yaml
中。
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: nodejs-knative-argocd
namespace: argocd
spec:
destination:
namespace: nodejs
server: 'https://kubernetes.default.svc'
source:
path: knative
repoURL: 'https://github.com/CIRCLECI-GWP/nodejs-knative-argocd'
targetRevision: circleci-project-setup
project: default
syncPolicy:
automated:
prune: false
selfHeal: false
提交并推送这些文件到您之前克隆的 GitHub 库的main
分支。
创建持续集成管道
本教程的目的是展示如何通过 CircleCI 的持续集成 (CI)和 ArgoCD 的持续部署 (CD)在 Kubernetes 上部署无服务器工作负载。
为了创建 CI 渠道,我们将使用 CircleCI 与您的 GitHub 帐户集成。CircleCI 配置以config.yml
文件的形式存在于项目根文件夹的.circleci
目录下,即配置的路径为.circleci/config.yml
。
config.yml
的内容是:
version: 2.1
orbs:
docker: circleci/docker@2.1.1
azure-aks: circleci/azure-aks@0.3.0
kubernetes: circleci/kubernetes@1.3.0
jobs:
argocd-manual-sync:
docker:
- image: cimg/base:stable
parameters:
server:
description: |
Server IP of of ArgoCD
type: string
username:
description: |
Username for ArgoCD
type: string
password:
description: |
Password for ArgoCD
type: string
steps:
- run:
name: Install ArgoCD CLI
command: |
URL=https://<< parameters.server >>/download/argocd-linux-amd64
[ -w /usr/local/bin ] && SUDO="" || SUDO=sudo
$SUDO curl --insecure -sSL -o /usr/local/bin/argocd $URL
$SUDO chmod +x /usr/local/bin/argocd
- run:
name: ArgoCD CLI login
command: argocd login << parameters.server >> --insecure --username << parameters.username >> --password << parameters.password >>
- run:
name: Manual sync
command: argocd app sync $APP_NAME
- run:
name: Wait for application to reach a synced and healthy state
command: argocd app wait $APP_NAME
argocd-configure:
docker:
- image: cimg/base:stable
parameters:
cluster-name:
description: |
Name of the AKS cluster
type: string
resource-group:
description: |
Resource group that the cluster is in
type: string
steps:
- checkout
- run:
name: Pull Updated code from repo
command: git pull origin $CIRCLE_BRANCH
- azure-aks/update-kubeconfig-with-credentials:
cluster-name: << parameters.cluster-name >>
install-kubectl: true
perform-login: true
resource-group: << parameters.resource-group >>
- kubernetes/create-or-update-resource:
resource-file-path: argocd/config.yaml
bump-docker-tag:
docker:
- image: cimg/base:stable
steps:
- run:
name: Install yq - portable yaml processor
command: |
URL=https://github.com/mikefarah/yq/releases/download/3.3.4/yq_linux_amd64
[ -w /usr/local/bin ] && SUDO="" || SUDO=sudo
$SUDO wget $URL
$SUDO mv ./yq_linux_amd64 /usr/local/bin/yq
$SUDO chmod +x /usr/local/bin/yq
- checkout
- run:
name: Update Knative Service manifest
command: |
yq w -i knative/service.yaml spec.template.metadata.name "$APP_NAME-$CIRCLE_BUILD_NUM"
yq w -i knative/service.yaml spec.template.spec.containers[0].image "docker.io/$DOCKER_LOGIN/$APP_NAME:$CIRCLE_SHA1"
- add_ssh_keys:
fingerprints:
- "$SSH_FINGERPRINT"
- run:
name: Commit & Push to GitHub
command: |
git config user.email "$GITHUB_EMAIL"
git config user.name "CircleCI User"
git checkout $CIRCLE_BRANCH
git commit -am "Bumps docker tag [skip ci]"
git push origin $CIRCLE_BRANCH
workflows:
Deploy-App-on-AKS:
jobs:
- docker/publish:
image: $DOCKER_LOGIN/$APP_NAME
tag: $CIRCLE_SHA1,latest
- bump-docker-tag:
requires:
- docker/publish
- argocd-configure:
cluster-name: $CLUSTER_NAME
resource-group: $RESOURCE_GROUP
requires:
- bump-docker-tag
# Paste the following only when you opt for the ArgoCD manual-sync-policy:
- argocd-manual-sync:
server: $ARGOCD_SERVER
username: $ARGOCD_USERNAME
password: $ARGOCD_PASSWORD
requires:
- argocd-configure
CI 工作流由 3 项工作组成:
docker/publish
作业构建容器并将其推送到 Dockerhubbump-docker-tag
作业用最新的容器图像标签更新 Knative 服务 YAMLargocd-configure
作业在 AKS 集群上应用 ArgoCD 配置- 只有当你选择
manual-sync-policy
时,才需要argocd-manual-sync
工作。对于automatic-sync
,你可以从文件中省略这项工作。
在这个工作流中,我们广泛使用了 CircleCI orbs ,它们是开源的、可共享的可参数化可重用配置元素包,包括作业、命令和执行器。orb 可以直接使用,也可以用于创建自定义作业。
提交并推送对 GitHub 库的更改。
在 CircleCI 建立项目
将应用程序部署到 AKS 的下一步是将 GitHub 存储库中的应用程序连接到 CircleCI。
进入你的 CircleCI 仪表盘,选择左边面板的项目选项卡。现在,您必须点击与包含代码的 GitHub 存储库(nodejs-knative-argocd)相对应的Set Up Project
按钮。
在选择您的 config.yml 文件屏幕上,选择最快选项并键入main
作为分支名称。CircleCI 会自动定位config.yml
文件。点击设置项目。
工作流将自动开始运行。但过一段时间后,它会将status
显示为Failed
。这是因为您必须设置一个用户密钥,并从 CircleCI 中的项目设置中配置环境变量。
要设置用户密钥,从项目设置的左侧面板中选择 SSH 密钥选项。在用户密钥部分,点击用 GitHub 授权。在工作流执行期间,CircleCI 需要用户密钥来代表存储库所有者将更改推送到您的 GitHub 帐户。
要配置环境变量,从项目设置的左侧面板中选择环境变量选项。选择添加环境变量选项。在下一个屏幕上,键入环境变量和您希望为其分配的值。
文件中使用的环境变量如下所示:
APP_NAME
:容器镜像名(nodejs-knative-argocd)ARGOCD_PASSWORD
: ArgoCD 门户密码ARGOCD_SERVER
: ArgoCD 服务器 IP 地址ARGOCD_USERNAME
: ArgoCD 门户用户名(管理员)AZURE_PASSWORD
: Azure 账号密码AZURE_USERNAME
: Azure 账号用户名CLUSTER_NAME
: AKS 集群名(NodeCluster)DOCKER_LOGIN
: Dockerhub 用户名DOCKER_PASSWORD
: Dockerhub 密码GITHUB_EMAIL
: GitHub 账号邮箱RESOURCE_GROUP
: AKS 资源组(NodeRG)SSH_FINGERPRINT
:用于将更新的 Docker 标签推送到 GitHub 的用户密钥的 SSH 指纹
要定位 SSH 指纹,进入项目设置,从侧边栏选择 SSH 密钥。向下滚动到用户密钥部分并复制密钥。
重新运行工作流。这次status
会显示Success
。
您还会发现另一条管道,其status
为Not Run
。这是因为您已经通过在提交消息中包含[skip ci]
明确指示 CircleCI 跳过管道。当 CircleCI 向 GitHub 提交更新后的配置文件时,[skip ci]
防止了工作流的自触发循环。
在 ArgoCD 仪表板上监控应用程序
当工作流重新运行时,显示Success
的status
表示应用程序已经部署在 AKS 集群上。
要观察和监视当前在 AKS 集群上运行的资源,请登录 ArgoCD 门户网站。
在本教程的前面部分,您学习了如何获取 ArgoCD 服务器 IP、用户名和密码以登录门户。登录后,您将进入应用程序页面。
单击应用程序名称。您将被重定向到一个页面,该页面包含 AKS 集群上运行的所有资源及其实时状态的树视图。
在 AKS 上访问应用程序
要访问该应用程序,您需要 Knative 服务创建的route
的 DNS 名称。
您在nodejs
名称空间中创建了所有的资源。要获取该命名空间中的所有资源,请使用以下命令:
kubectl get all --namespace nodejs
将URL
复制为service.serving.knative.dev/nodejs-knative-argocd
。
使用此 URL 访问应用程序。对我来说,网址是http://nodejs-knative-argocd.nodejs.52.146.24.47.sslip.io/
。
结论
本教程到此结束。通过遵循本指南,您学习了如何开发一个自动化的 CI 管道,用于在 Kubernetes 集群上持续部署您的无服务器工作负载,遵循 Knative 和 ArgoCD 的 GitOps 实践。一旦正确配置了管道,对应用程序代码所做的任何更改都会立即反映在工作负载 URL 上。不再需要在 Kubernetes 上手动配置和部署应用程序。您可以更改环境变量的值,以便将 CircleCI 配置文件用于类似的应用程序。
本教程的完整源代码也可以在 GitHub 上找到。
Avik Kundu 是 Red Hat 的一名软件工程师。他是全栈开发人员、开源贡献者和精通 DevOps 和云的技术内容创建者。他是 AWS 社区构建者和 Microsoft Learn 学生大使。他写过关于媒体、开发和 Opensource.com 的各种工具和技术的文章和教程。他喜欢学习新技术,并在公共场合分享他的知识。
将一个苗条的应用程序自动部署到 Heroku | CircleCI
随着 React 、 Vue 和 Angular 成为 Javascript 前端框架的中心,许多人认为我们已经达到了 Javascript 框架的平衡。然后是svelet通过解决其他前端框架解决的相同问题,以一种独特的方式,再次扰乱了框架空间。与其他框架不同,Svelte 不使用虚拟 DOM 在浏览器中更新 DOM。相反,它在构建步骤中编译高效的 Javascript 代码,在状态发生变化时高效地更新您的 DOM。在本教程中,我们将创建一个自动连续部署(CD)管道,将我们的苗条应用程序部署到 Heroku 。
先决条件
要完成本教程,需要做一些事情:
所有这些安装和设置,让我们开始教程。
创建一个苗条的项目
首先,我们需要创建我们的苗条项目。在系统中选择一个适当的位置,并运行以下命令来创建一个新项目:
npx degit sveltejs/template svelte-heroku-app
这个命令的svelte-heroku-app
部分是我想要保存项目脚手架的文件夹名。你可以使用任何你喜欢的名字。
这个命令将立即开始搭建一个新的苗条项目。一旦搭建过程完成,进入项目的根目录(cd svelte-heroku-app
)并运行npm install
来安装所需的包。安装完成后,运行以下命令启动服务器,为开发模式下的应用程序提供服务:
npm run dev
这将在http://localhost:5000/
地址为应用程序提供服务(5000
是默认端口,除非它在使用中,然后将使用另一个端口代替)。
我们现在有了一个实用的苗条应用程序。
设置 Heroku 以部署苗条的应用程序
要设置 Heroku 应用程序,我们需要登录我们的帐户并创建一个新的应用程序。
接下来,我们需要获得我们的应用程序的名称(对于上面创建的应用程序,这将是svelte-heroku-app
)和我们帐户的 API 密钥。API 密匙可以在 Heroku 账户设置部分找到。我们稍后将需要这两个值(应用程序名称和 API 密钥)来在 CircleCI 上创建环境变量,以便部署到 Heroku。
当我们打开 Heroku 帐户时,我们需要做的最后一件事是安装必要的构建包。构建包是在部署应用程序时运行的脚本。本教程需要两个构建包:
heroku/nodejs
:所有 Node.js 应用程序都需要- Heroku buildpack 静态包。
注意 : heroku/heroku-buildpack-static
是需要的,因为一个苗条的应用程序是通过一个完全由静态文件组成的public
文件夹提供的,这将帮助我们在 Heroku 平台上提供静态文件。
进入你的 Heroku 应用程序设置页面,向下滚动到构建包部分(你可能已经看到已经添加的heroku/nodejs
构建包)。点击添加构建包。
对于每个构建包(heroku/nodejs
和heroku/heroku-buildpack-static
),在文本字段中输入标识符/URL,然后点击保存更改。
注意: 如果已经添加了heroku/nodejs
buildpack,只需添加heroku/heroku-buildpack-static
buildpack 即可。
在对两个构建包都做了这些之后,您将会在 buildpacks 部分看到这两个包。
现在我们已经完成了 Heroku 上所有需要的设置。
在 CircleCI 建立苗条项目
我们的下一个任务是在 CircleCI 建立我们的苗条项目。从将你的项目推送到 GitHub 开始。
接下来,转到 CircleCI 仪表板上的添加项目页面。
点击设置项目开始。
接下来,点击手动添加。您会得到提示,要么下载管道的配置文件,要么开始构建。
点击开始建造。这个构建将会失败,因为我们还没有设置配置文件。我们稍后再做。
我们需要在 CircleCI 控制台上做的最后一件事是为我们刚刚添加的项目设置环境变量。这将使它能够对我们的 Heroku 应用程序进行身份验证访问,以进行部署。
点击管道页面上的项目设置(右上角)进入您的项目设置(确保您的项目是当前选择的项目)。
在这个页面上,点击侧面菜单上的环境变量。
在环境变量页面中,点击添加环境变量。
添加以下环境变量:
HEROKU_APP_NAME
:这是您的 Heroku 应用程序的名称(在本例中为svelte-heroku-app
)- 您的 Heroku 帐户 API 密钥。
注 : 如前所述,这可以在你的 Heroku 账户的账户标签下的账户设置下找到。
添加完成后,您现在已经在 CircleCI 控制台上为部署到 Heroku 做好了一切准备。
使用 CircleCI Heroku orb 部署苗条应用程序
CircleCI orbs 是 YAML 配置的可重用包,它将重复的配置压缩成一行代码。它们使开发人员能够在抽象出所有样板文件的情况下轻松使用强大的管道功能。
在本练习中,我们将使用 CircleCI 的 orb for Heroku 来编写一个管道配置,以将我们的苗条站点部署到 Heroku。
但在此之前,我们需要创建一个文件来指导我们的 Heroku Buildpack 静态包如何部署和服务我们的应用程序。在项目的根目录下,创建一个名为static.json
的新文件,并输入以下代码:
{
"root": "public/",
"https_only": true
}
这里最重要的配置参数是root
属性。一个苗条的应用程序是通过一个public
文件夹提供的。因此,root
属性用于指向该文件夹,以便主机提供适当的代码。https_only
旨在确保我们的应用始终通过安全协议提供服务。
现在我们可以编写部署脚本了。在 Svelte 项目的根目录下,创建一个名为.circleci
的文件夹,并在其中创建一个名为config.yml
的文件。在config.yml
文件中,输入以下代码:
version: 2.1
orbs:
heroku: circleci/heroku@0.0.10
workflows:
heroku_deploy:
jobs:
- heroku/deploy-via-git
在上面的配置中,我们引入了 Heroku orb ( circleci/heroku@0.0.10
),它自动为我们提供了一组强大的 Heroku 任务和命令。其中一项工作是heroku/deploy-via-git
,它将应用程序直接从 GitHub repo 部署到 Heroku 帐户。这项工作已经负责安装 Heroku CLI、安装项目依赖项、运行构建脚本和部署应用程序。它还获取我们的环境变量,以便顺利部署到我们的 Heroku 应用程序。
现在,是我们一直在等待的时候了:部署点。让我们提交对我们的苗条项目所做的所有更改,并推动我们的 repo 来触发部署。
要查看部署的幕后情况,您可以点击heroku/deploy-via-git
查看构建。
关于我们的 Svelte 应用程序已经成功部署的官方确认,请访问站点https://[APP_NAME].herokuapp.com
的默认 Heroku 地址。对于这个练习,它将是https://svelte-heroku-app.herokuapp.com/
。
厉害!
我们现在在 Heroku 上有了一个苗条的应用程序。
结论
我们已经能够使用 CircleCI orbs 成功地将一个苗条的应用程序部署到 Heroku,以构建一个自动化的连续部署管道。现在,我们需要做的就是将更新部署到我们的应用程序中,然后推送我们的代码,所有的更改都会自动部署。本练习还演示了 CircleCI orbs 如何简化部署设置。
查看 CircleCI orbs registry 中适合您的编程语言和部署选择的 orbs。
编码快乐!
Fikayo Adepoju 是 LinkedIn Learning(Lynda.com)的作者、全栈开发人员、技术作者和技术内容创建者,精通 Web 和移动技术以及 DevOps,拥有 10 多年开发可扩展分布式应用程序的经验。他为 CircleCI、Twilio、Auth0 和 New Stack 博客撰写了 40 多篇文章,并且在他的个人媒体页面上,他喜欢与尽可能多的从中受益的开发人员分享他的知识。你也可以在 Udemy 上查看他的视频课程。
使用 Terraform | CircleCI 通过批准作业部署基础架构
原文:https://circleci.com/blog/deploy-terraform-behind-approval-job/
如果你正在寻找一个基础设施即代码(IaC)工具,那么 Terraform 可能是你的首选。在本教程中,您将学习如何使用 Terraform 和 CircleCI 工作流自动部署基础架构变更。工作流将使用批准工作。对于这个项目,我们将把我们构建的基础设施部署到谷歌云平台 (GCP)。即使你使用另一家云提供商,如 DigitalOcean 或 Amazon Web Services (AWS),你也能够适应并应用你在这里学到的东西。
注: 我将在本教程的稍后部分更详细地描述 Terraform 的功能。
先决条件
要遵循本教程,需要做一些事情:
关于 CircleCI 工作流程
CircleCI 工作流是一种声明性的方式,用于指定一系列作业应该如何、何时以及以何种顺序在管道中运行。在本教程中,我们将使用 CircleCI 工作流在每次提交 GitHub 存储库的主分支时部署我们的基础设施变更。
关于 Terraform
Terraform 是一个工具,它允许我们使用用一种叫做 Hashicorp 配置语言 (HCL)的专门编程语言编写的配置文件来编写基础设施。HCL 配置文件使用.tf
扩展名。
我们将使用 Terraform 来编写 resources
。Terraform 资源是基础设施资源的代码表示。资源可以是服务器、防火墙规则、网络地址或基础设施的另一部分。
为了保持资源与云提供商运行的资源同步,Terraform 使用了一个 state
。状态可以存储在不同的后端:本地、远程存储服务或状态管理软件。
安装 Terraform CLI
我发现安装 Terraform CLI 最简单的方法是从官方下载页面的下载为您的平台预先构建的二进制文件,并将其移动到当前位于您的PATH
环境变量中的文件夹。
注意 : Terraform 提供大量关于安装的文档,如果你想尝试不同的方法。
例如,在 Linux 上,安装 Terraform 就像运行以下命令一样简单:
wget -O terraform.zip https://releases.hashicorp.com/terraform/0.13.5/terraform_0.13.5_linux_amd64.zip
unzip terraform.zip && rm terraform.zip
sudo mv terraform /usr/local/bin/
通过运行以下命令确认安装正确:
terraform version
它应该会打印出类似于Terraform v0.13.5
的内容(Terraform 会定期更新,所以如果您的版本有所不同,请不要感到惊讶)
既然 Terraform 已经开始工作了,我们可以创建我们的项目了。
设置 Google 云
我们的第一个任务是在 Google Cloud 上创建一个项目来存储与 Terraform 本身相关的一切,比如状态和服务账户。使用 gcloud CLI 输入:
注意 : 请在运行以下命令之前,通过运行gcloud auth login
确认您已登录(使用适当的 Google 帐户),它会重定向到您的默认浏览器供您登录。
如果您使用的是 Linux/Unix:
RANDOM_ID=$(perl -pe 'binmode(STDIN, ":bytes"); tr/a-z0-9//dc;' < /dev/urandom | head -c 8; echo)
gcloud projects create terraform-admin-$RANDOM_ID --name terraform-admin --set-as-default
如果您在 Windows 上(并且没有使用 Linux 的 WSL - Windows 子系统),请改为运行以下命令:
set RANDOM_ID=%random%%random%
gcloud projects create terraform-admin-%RANDOM_ID% --name terraform-admin --set-as-default
第一行创建了一个随机 id,我们可以用它作为 Google Cloud 上项目 ID 的后缀。使用随机 ID 作为后缀很重要,因为项目 ID 必须是唯一的。第二行在 Google Cloud 上创建项目。我们把它命名为terraform-admin
。
如果您正在使用 Google Cloud 上的一个组织,并且您希望这个项目成为它的一部分,请将该组织添加到上面的 gcloud 命令中,就像这样:--organization [org-id]
。
该命令的最后输出应该类似于:
Updated property [core/project] to [terraform-admin-0bqjep28]
为了使接下来的步骤更容易,我们可以将完整的项目标识符放在一个变量中:
export TERRAFORM_PROJECT_IDENTIFIER=$(gcloud config get-value project)
运行以下命令,将最近创建的项目链接到您的计费帐户:
gcloud beta billing projects \
link $TERRAFORM_PROJECT_IDENTIFIER \
--billing-account [billing-account-id]
记得用您的账单账户的的实际 ID 替换billing-account-id
。如果不知道使用什么 ID,最简单的方法是运行:
gcloud beta billing accounts list
您的 ID 是输出的第一列。使用打开状态(第三列)为真的 ID。
接下来,在 Terraform 项目上启用所需的 API:
gcloud services enable \
cloudresourcemanager.googleapis.com \
cloudbilling.googleapis.com \
compute.googleapis.com \
iam.googleapis.com \
serviceusage.googleapis.com \
container.googleapis.com
创建服务帐户
创建我们将与 Terraform 一起使用的服务帐户:
gcloud iam service-accounts create terraform \
--display-name "Terraform admin account"
它应该显示如下内容:
Created service account [terraform].
将服务帐户电子邮件存储在变量中:
export TERRAFORM_SERVICE_ACCOUNT_EMAIL="terraform@$TERRAFORM_PROJECT_IDENTIFIER.iam.gserviceaccount.com"
创建服务帐户 JSON 密钥
创建服务帐户后,我们需要一个 JSON 键。JSON 密钥是我们将用来作为此服务帐户进行身份验证的文件:
gcloud iam service-accounts keys create \
--iam-account $TERRAFORM_SERVICE_ACCOUNT_EMAIL \
~/gcloud-terraform-admin.json
您应该会得到类似如下的输出:
created key [d4a3ef60690cb42faa1a71c5d75c5c04f6535c5a] of type [json] as [~/gcloud-terraform-admin.json] for [terraform@terraform-admin-0bqjep28.iam.gserviceaccount.com]
输出显示 Terraform 服务帐户密钥是在~/gcloud-terraform-admin.json
创建的。记住这条路,因为我们以后会需要它。
添加角色
接下来,我们需要创建角色,以便 Terraform 可以将它们的状态存储在我们稍后将创建的存储桶中。在这一步中,我们将把viewer
和storage.admin
角色添加到 Terraform Google Cloud 项目的服务帐户中:
gcloud projects add-iam-policy-binding $TERRAFORM_PROJECT_IDENTIFIER \
--member serviceAccount:$TERRAFORM_SERVICE_ACCOUNT_EMAIL \
--role roles/viewer
gcloud projects add-iam-policy-binding $TERRAFORM_PROJECT_IDENTIFIER \
--member serviceAccount:$TERRAFORM_SERVICE_ACCOUNT_EMAIL \
--role roles/storage.admin
它应该在每个命令之后输出项目的更新 IAM 策略。
地形状态可以本地存储,也可以远程存储。如果你是团队的一员,或者使用多台机器,远程存储效果最好。因为我们使用的是 Google Cloud,所以我们将状态直接存储在一个存储桶中。要在 Google Cloud 上创建 bucket,运行:
gsutil mb -p $TERRAFORM_PROJECT_IDENTIFIER gs://$TERRAFORM_PROJECT_IDENTIFIER
gsutil versioning set on gs://$TERRAFORM_PROJECT_IDENTIFIER
如果您跳过了前面的步骤,将项目链接到您的计费帐户,您将得到类似于:Error: Failed to get existing workspaces: querying Cloud Storage failed: storage: bucket doesn't exist
的错误
bucket 名称必须是惟一的,所以我们使用了项目标识符。我们还在存储桶中启用了版本控制。
现在只剩下几个步骤来完成谷歌云的配置。
创建一个单独的项目来创建我们的 Kubernetes 集群:
gcloud projects create circleci-k8s-cluster-$RANDOM_ID --name circleci-k8s-cluster
请注意,我们使用的是我们在之前的项目中使用的命令,但是我们使用的是名称circleci-k8s-cluster
。另一个区别是,我们没有将此项目设置为 gcloud CLI 的默认项目。
将标识符放入变量中,就像我们之前做的那样:
export CIRCLECI_K8S_CLUSTER_PROJECT_IDENTIFIER=circleci-k8s-cluster-$RANDOM_ID
就像 Terraform 项目一样,新项目必须链接到您的计费帐户。运行:
gcloud beta billing projects \
link $CIRCLECI_K8S_CLUSTER_PROJECT_IDENTIFIER \
--billing-account [billing-account-id]
记得用您的付费帐户 ID 替换[billing-account-id
]。
要完成 Google Cloud 设置,请授予 Terraform 服务帐户对此项目的完全访问权限。给它分配owner
角色:
gcloud projects add-iam-policy-binding $CIRCLECI_K8S_CLUSTER_PROJECT_IDENTIFIER \
--member serviceAccount:$TERRAFORM_SERVICE_ACCOUNT_EMAIL \
--role roles/owner
保护项目资源的安全
凭借owner
权限,Terraform 服务帐户可以完全访问该项目及其所有资源。对服务帐户密钥格外小心可能是明智的。
如果您在 Google Cloud 上有一个组织,您也可以在组织级别为服务帐户赋予类似的角色。这使得 Terraform 服务帐户可以访问该组织内的所有项目。我还建议将resourcemanager.projectCreator
和roles/billing.user
角色赋予组织级别的服务帐户。授予这些角色访问权限,可以让 Terraform 自己在 Google Cloud 上创建新项目。对于本教程,我们需要手动创建项目,然后才能在 Terraform 中使用它们。
现在我们可以转移到 Terraform 项目本身。
将我们的基础设施创建为代码项目
对于本教程,我们将部署一个简单的 Kubernetes 集群到 Google Cloud。我们需要做的第一件事是在 GitHub 上创建我们的存储库,并在我们的机器上初始化一个指向这个 repo 的本地存储库。将您的项目命名为circleci-terraform-automated-deploy
。
使用 GitHub CLI,这就像运行:
gh repo create circleci-terraform-automated-deploy
将Visibility
设置为您想要的,并回答两个问题的Yes
。
转到新存储库:
cd circleci-terraform-automated-deploy
创建新文件:
.
|- backend.tf
|- k8s-cluster.tf
|- main.tf
|- outputs.tf
|- variables.tf
创建每个文件,将它们留空:
touch backend.tf k8s-cluster.tf main.tf outputs.tf variables.tf
以下是每个文件的描述:
- 设置存储我们状态的后端
k8s-cluster.tf
为 Kubernetes 相关资源main.tf
代表资源和配置,比如我们正在使用的提供商variables.tf
对于本教程将为空outputs.tf
对于本教程也是空的
通过添加以下内容更新backend.tf
:
terraform {
backend "gcs" {
bucket = "[full-project-identifier]"
prefix = "terraform/state"
}
}
记得用 Terraform 正在使用的 Google 项目的完整标识符替换[full-project-identifier]
。它存储在$TERRAFORM_PROJECT_IDENTIFIER
shell 变量中。我们将我们的 bucket 命名为与项目标识符完全相同的名称,因此它具有相同的值。
最后,我们将导出一个名为GOOGLE_APPLICATION_CREDENTIALS
的新 shell 变量。我们在 Terraform 中使用的google
提供者检查这个变量以进行身份验证。新变量指向我们之前创建的服务帐户密钥:
export GOOGLE_APPLICATION_CREDENTIALS=~/gcloud-terraform-admin.json
检查 Terraform 是否能够通过 Google Cloud 进行身份验证,以创建初始状态。在您的 git 存储库中,运行:
terraform init
如果失败,尝试运行terraform init -reconfigure
您应该会看到多行输出,包括:
Terraform 已成功初始化!
Terraform 在当前目录下创建了一个.terraform
文件夹。我们不想将它提交给我们的存储库,所以将其添加到.gitignore
:
echo ".terraform" >> .gitignore
现在我们可以使用 Terraform 创建我们的 Kubernetes 集群。首先,让 Terraform 知道我们想要使用哪个版本的谷歌 Terraform 提供商。打开main.tf
并添加:
provider "google" {
project = "[circleci-project-full-identifier]"
region = "us-west1"
}
除了 Google provider 的版本,我们还设置了project
和region
的默认值。创建资源时,默认情况下将使用这些值。确保用实际值替换[circleci-project-full-identifier]
。在我们的例子中,这是$CIRCLECI_K8S_CLUSTER_PROJECT_IDENTIFIER
shell 变量的值。
因为我们改变了一个提供者,我们也必须重新初始化 Terraform 状态。运行:
terraform init
您的输出应该包括:
Terraform 已成功初始化!
Terraform 资源基于实际的基础设施资源,因此要在 Google Cloud 上创建 Kubernetes 集群,我们必须创建两个资源:
链接指向每个资源的 Terraform 文档。
在存储库中创建一个名为k8s-cluster.tf
的新文件(如果还没有创建的话):
touch k8s-cluster.tf
用你最喜欢的编辑器打开它,写下:
locals {
k8s_services = [
"cloudapis.googleapis.com",
"cloudresourcemanager.googleapis.com",
"cloudtrace.googleapis.com",
"compute.googleapis.com",
"container.googleapis.com",
"dataflow.googleapis.com",
"logging.googleapis.com",
"monitoring.googleapis.com",
"pubsub.googleapis.com",
"replicapool.googleapis.com",
"replicapoolupdater.googleapis.com",
"servicemanagement.googleapis.com",
"serviceusage.googleapis.com",
]
}
resource "google_project_service" "k8s_cluster" {
count = length(local.k8s_services)
service = local.k8s_services[count.index]
disable_dependent_services = true
}
resource "google_container_cluster" "circleci_cluster" {
name = "circleci-cluster"
location = "us-west1-a"
# Kubernetes Version
min_master_version = "1.17.13-gke.2600"
# We can't create a cluster with no node pool defined, but we want to use
# a separately managed node pool. For that, we create the smallest possible
# default node pool and immediately delete it.
# This is the recommended way to manage node pools with Terraform.
remove_default_node_pool = true
initial_node_count = 1
# Setting an empty username and password explicitly disables basic auth
master_auth {
username = ""
password = ""
client_certificate_config {
issue_client_certificate = false
}
}
depends_on = [
google_project_service.k8s_cluster
]
}
resource "google_container_node_pool" "circleci_cluster_primary" {
name = "primary"
location = google_container_cluster.circleci_cluster.location
cluster = google_container_cluster.circleci_cluster.name
node_count = 1
node_config {
machine_type = "e2-standard-2"
oauth_scopes = [
"https://www.googleapis.com/auth/devstorage.read_only",
"https://www.googleapis.com/auth/logging.write",
"https://www.googleapis.com/auth/monitoring",
"https://www.googleapis.com/auth/service.management.readonly",
"https://www.googleapis.com/auth/servicecontrol",
"https://www.googleapis.com/auth/trace.append",
]
}
}
准备好 Terraform 配置文件后,我们可以测试 Terraform action planner 将为我们引入的更改输出什么:
terraform plan
如果一切正常,您应该会看到多行输出,显示当前状态和.tf
文件中的不同。它还应该给出变化的摘要:
计划:15 添加,0 更改,0 销毁。
Terraform 计划向我们的州添加 15 个资源,并通过这样做,在谷歌云上创建它们。
应用更改:
terraform apply
现在,Terraform 将显示相同的差异,但它不会在最后退出,而是提示您应用这些更改:
计划:15 添加,0 更改,0 销毁。您想执行这些操作吗?Terraform 将执行上述操作。只有“是”将被接受批准。
回答yes
。
Terraform CLI 成功退出后,Google Cloud 上的资源就准备好了。通过访问谷歌云控制台并转到Kubernetes Engine
页面来确认这一点。
如果引用一个声称版本不受支持的 google api 错误不成功,请在此参考在 GKE 可用的最新次要版本,并用常规 GKE 发布渠道的默认补丁版本更新k8s-cluster.tf
的第 30 行;然后重新运行terraform apply
。
希望现在一切正常。我们将通过运行以下命令来破坏我们的基础设施:
terraform destroy
输出应包括:
计划:0 添加,0 更改,15 销毁。
真的要破坏所有资源吗?Terraform 会毁掉你所有的托管基础设施,如上图。无法撤销。只接受“是”进行确认。
回答yes
整个基础设施将被摧毁,并从国家中移除。
现在是将一切提交给我们的存储库的好时机。不过,在此之前,还有一个非常有用的 Terraform 命令。在项目根目录下,运行:
terraform fmt
这个命令将我们的.tf
文件重写为规范的格式。
提交您的更改:
git add --all
git commit -m "terraform initial files"
git push -u origin master
创建我们的 CircleCI 配置
为了使我们的 CircleCI 配置更容易,我们将使用一个 CircleCI Orb 。orb 是可重用的代码片段,有助于自动化重复的过程,加速项目设置,并使其易于与第三方工具集成。我们要用的宝珠是 CircleCI 的官方 Terraform 宝珠: circleci/terraform 。
在 git 存储库的根目录下创建一个名为.circleci
的新文件夹。添加一个名为config.yml
的空文件:
mkdir .circleci
touch .circleci/config.yml
写:
version: 2.1
orbs:
terraform: "circleci/terraform@1.1.0"
workflows:
deploy_infrastructure:
jobs:
- terraform/fmt:
checkout: true
context: terraform
- terraform/validate:
checkout: true
context: terraform
requires:
- terraform/fmt
- terraform/plan:
checkout: true
context: terraform
persist-workspace: true
requires:
- terraform/validate
- terraform/apply:
attach-workspace: true
context: terraform
filters:
branches:
only: master
requires:
- terraform/plan
我们正在使用 circleci/terraform
orb 中的多个作业来为我们完成繁重的工作。工作流会做所有的事情。
对于每次提交,它将验证我们的.tf
文件是否被正确格式化(terraform/fmt
作业)以及它们是否有效(terraform/validate
作业)。工作流还计划了我们对基础设施所做的更改(terraform/plan
job)。
如果提交是在master
分支中,我们将apply
在terraform/plan
作业中计划的变更。
这已经是很多自动化了。我们可能不希望在未经某人直接批准的情况下对我们的基础设施进行更改。
需要批准
要在应用更改之前获得批准,我们需要对.circleci/config.yml
文件进行更改:
version: 2.1
orbs:
terraform: "circleci/terraform@1.1.0"
workflows:
deploy_infrastructure:
jobs:
- terraform/fmt:
checkout: true
context: terraform
- terraform/validate:
checkout: true
context: terraform
requires:
- terraform/fmt
- terraform/plan:
checkout: true
context: terraform
persist-workspace: true
requires:
- terraform/validate
- hold-apply:
type: approval
requires:
- terraform/plan
- terraform/apply:
attach-workspace: true
context: terraform
filters:
branches:
only: master
requires:
- hold-apply
我们在工作流程中引入了一项新的审批工作。该作业将暂停我们的工作流,直到有人批准或取消该请求。现在我们的terraform/apply
任务要求hold-apply
任务在开始前得到批准。
批准后,terraform/apply
作业将开始运行。
将目前为止的所有更改提交到我们的存储库:
git add --all
git commit -m "add circleci config"
git push
在 CircleCI 建立项目
当你登录到你的 CircleCI 账户后,点击侧边栏中的Organization Settings
页面。现在我们可以在名为terraform
的配置文件中添加我们正在使用的上下文。上下文是一种在 CircleCI 中跨多个项目/作业安全共享环境变量的方式。
在下一页Contexts
中,点击Create Context
。将上下文命名为terraform
,并点击Create Context
。从列表中选择新上下文以查看其详细信息。
点击Add Environment Variable
。将环境变量命名为GOOGLE_CREDENTIALS
。变量的值是我们的 terraform 服务帐户的.json
键的全部内容。我们将该文件保存到~/gcloud-terraform-admin.json
。要获取内容,请运行:
cat ~/gcloud-terraform-admin.json
将环境变量的值设置为 JSON 密钥文件的内容后,单击Add Environment Variable
。
现在我们已经完成了上下文的创建,返回到 CircleCI 中的项目页面(通过点击右上角的 X 图标)。搜索您为基础设施创建的 GitHub 存储库。点击Set Up Project
。
点击Use Existing Config
。
然后Start Building
。
这将运行我们存储库的第一次构建。
如果一切正常,UI 将显示一个不同的图标,它到达hold-apply
任务。
点击terraform/plan
任务,查看terraform plan
步骤的输出。如果正确,返回工作流程页面,点击hold-apply
作业。您可以批准或取消它。
批准它开始terraform/apply
。
这项工作可能需要一段时间才能完成。一旦它结束,基础设施应该可以在谷歌云控制台上使用,我们的建设将是绿色的。
成功!
当您不再需要基础结构时,您可以运行(本地):
terraform destroy
结论
通过 Terraform 将基础设施作为代码使用,不仅可以提高应用新变更的速度,还可以跟踪这些变更的所有权。使用 CircleCI 自动部署所有这些将使您的基础设施更加可靠,同时提供高效的软件开发生命周期。
Jonathan Cardoso 热衷于 DevOps、开源和游戏。他有六年的经验,帮助世界各地的公司通过技术解决方案推进他们的目标。他目前在巴西担任 HelloMD 的全栈开发人员和 DevOps 专家。
使用 CI/CD 在 Kubernetes 上部署 web 应用程序
原文:https://circleci.com/blog/deploy-to-kubernetes-with-argocd/
本教程涵盖:
- 在 Azure Kubernetes 服务上部署 Node.js 应用程序
- 使用 orbs(YAML 配置的可重用包)创建持续集成管道
- 自动化 ArgoCD 以将最新的应用程序版本部署到 Kubernetes 集群
GitOps 通过允许开发人员使用单一的事实来源(通常是 Git 存储库)来声明性地管理基础设施和代码,使软件管理和操作现代化。许多开发团队和组织已经采用 GitOps 过程来改进软件应用程序的创建和交付。
要让 GitOps 计划成功,像 Kubernetes 这样的编排系统是至关重要的。开发软件所需的大量不兼容技术使得 Kubernetes 成为管理基础设施的关键工具。没有 Kubernetes,实现基础设施即代码(IaC)的过程是低效的,甚至是不可能的。幸运的是,Kubernetes 的广泛采用使得实现 GitOps 的工具得以创建。
这些工具之一, ArgoCD ,是一个 Kubernetes-native 连续部署(CD)工具。它可以通过从 g it 存储库而不是外部 CD 解决方案中提取代码更改来直接将代码更改部署到 Kubernetes 资源中。其中许多解决方案仅支持基于推送的部署。使用 ArgoCD 使开发人员能够从一个统一的平台控制应用程序更新和基础设施设置。它处理 GitOps 过程的后期阶段,确保新的配置被正确地部署到 Kubernetes 集群。
在本教程中,您将学习如何使用 CI/CD 管道和 ArgoCD 在 Azure Kubernetes Service (AKS)上部署 Node.js 应用程序。
先决条件
要跟随本教程,您首先需要一些东西。
占:
安装在您系统上的这些工具:
我们的教程是平台无关的,但是使用 CircleCI 作为例子。如果你没有 CircleCI 账号,请在 注册一个免费的 。
完成所有先决条件后,您就可以进入下一部分了。
克隆 Node.js 应用程序
在本教程中,主要重点是在 Kubernetes 上部署应用程序。你可以直接将 Node.js 应用克隆到你的 GitHub,并继续剩下的过程。
要克隆项目,请运行:
git clone https://github.com/CIRCLECI-GWP/aks-nodejs-argocd.git
该存储库中有两个分支:
main
分支只包含 Node.js 应用程序代码- 分支包含应用程序代码以及您将创建的所有 YAML 文件
检查到main
分支。
Node.js 应用程序位于app.js
文件中,包含:
const express = require("express");
const path = require("path");
const morgan = require("morgan");
const bodyParser = require("body-parser");
/* eslint-disable no-console */
const port = process.env.PORT || 1337;
const app = express();
app.use(morgan("dev"));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: "true" }));
app.use(bodyParser.json({ type: "application/vnd.api+json" }));
app.use(express.static(path.join(__dirname, "./")));
app.get("*", (req, res) => {
res.sendFile(path.join(__dirname, "./index.html"));
});
app.listen(port, (err) => {
if (err) {
console.log(err);
} else {
console.log(`App at: http://localhost:${port}`);
}
});
module.exports = app;
这段代码的关键是端口号,这是应用程序将要运行的地方,对于本教程来说是1337
。
通过首先安装依赖项,您可以在本地运行应用程序。在项目的根目录中,键入:
npm install
然后使用以下命令运行应用程序:
node app.js
应用程序现在应该在地址http://localhost:1337
启动并运行。
容器化 Node.js 应用程序
要部署 Kubernetes 的应用程序,您需要将其容器化。要使用 Docker 作为容器运行时工具来容器化应用程序,您将创建一个 Dockerfile 。Dockerfile 是一个文本文档,它包含用户可以在命令行上调用的所有命令来组合一个图像。
在项目的根目录下创建一个新文件,命名为Dockerfile
。复制文件中的以下内容:
# Set the base image to use for subsequent instructions
FROM node:alpine
# Set the working directory for any subsequent ADD, COPY, CMD, ENTRYPOINT,
# or RUN instructions that follow it in the Dockerfile
WORKDIR /usr/src/app
# Copy files or folders from source to the dest path in the image's filesystem.
COPY package.json /usr/src/app/
COPY . /usr/src/app/
# Execute any commands on top of the current image as a new layer and commit the results.
RUN npm install --production
# Define the network ports that this container will listen to at runtime.
EXPOSE 1337
# Configure the container to be run as an executable.
ENTRYPOINT ["npm", "start"]
如果您已经安装了 Docker ,那么您可以在本地构建并运行容器进行测试。在本教程的后面,您将学习如何使用 CircleCI orbs 自动完成这个过程。
要构建和标记容器,请输入:
docker build -t aks-nodejs-argocd:latest .
通过从终端运行以下命令,确认映像已成功创建:
docker images
然后使用以下命令运行容器:
docker run -it -p 1337:1337 aks-nodejs-argocd:latest
应用程序现在应该在地址http://127.0.0.1:1337
启动并运行。
提交并推送对 GitHub 库的更改。
为部署配置 Kubernetes 清单
要在 Kubernetes 上部署容器,您必须配置 Kubernetes,以包含运行应用程序所需的所有设置。Kubernetes 使用 YAML 进行配置。
在项目的根目录下创建一个名为manifests
的目录。然后在新创建的文件夹中创建这些文件:
namespace.yaml
deployment.yaml
service.yaml
kustomization.yaml
在 Kubernetes 中,名称空间提供了一种在单个集群中隔离资源组的机制。namespace.yaml
的内容:
apiVersion: v1
kind: Namespace
metadata:
name: nodejs
labels:
name: nodejs
这个文件将在 Kubernetes 集群中创建一个名为nodejs
的名称空间。所有资源都将在这个名称空间中创建。
Kubernetes 部署管理集群上运行的无状态服务。他们的目的是保持一组相同的 pod 运行,并以受控的方式升级它们——默认情况下执行滚动更新。deployment.yaml
的内容:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nodejs
namespace: nodejs
labels:
app: nodejs
spec:
replicas: 3
selector:
matchLabels:
app: nodejs
template:
metadata:
labels:
app: nodejs
spec:
nodeSelector:
"beta.kubernetes.io/os": linux
containers:
- name: aks-nodejs-argocd
image: aks-nodejs-argocd
ports:
- name: http
containerPort: 1337
这段代码的关键是containerPort
。这是应用程序运行的地方,也是在 Kubernetes 集群的名称空间中提取和部署container-image
的地方。
Kubernetes 服务是一个抽象,它定义了一组逻辑 pod 和访问它们的策略。您需要 Kubernetes 服务类型LoadBalancer
来使外部世界可以访问部署。
service.yaml
的内容有:
apiVersion: v1
kind: Service
metadata:
name: nodejs
namespace: nodejs
labels:
app: nodejs
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 1337
selector:
app: nodejs
这段代码的关键是targetPort
、port
和type
:
targetPort
是集装箱港口port
是应用程序将要运行的地方type
是服务的类型
要在 Kubernetes 集群上部署最新版本的应用程序,必须定制资源来维护更新的信息。你可以使用 Kustomize ,这是一个定制 Kubernetes 配置的工具。
kustomization.yaml
的内容是:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
- namespace.yaml
namespace: nodejs
images:
- name: aks-nodejs-argocd
newName: aks-nodejs-argocd
newTag: v1
这段代码的关键是newName
和newTag
,作为持续集成过程的一部分,它们将使用最新的 Docker 图像信息进行更新。
提交并推送这些文件到您之前克隆的 GitHub 库的main
分支。
启动 Azure Kubernetes 服务(AKS)群集
在本教程中,您将在 AKS 集群上部署应用程序。要创建 AKS 集群,Azure CLI 应该连接到您的 Azure 帐户。
要使用 Azure CLI 启动 AKS 群集,请使用以下命令创建资源组:
az group create --name NodeRG --location eastus
启动双节点集群:
az aks create --resource-group NodeRG --name NodeCluster --node-count 2 --enable-addons http_application_routing
注意: 如果您之前在系统中生成了任何 SSH 密钥,那么您需要在这个命令中添加可选的--generate-ssh-keys
参数。如果缺少 SSH 公钥和私钥文件,这会自动生成它们。密钥存储在~/.ssh
目录中。
AKS 群集将需要 10 到 15 分钟才能启动。
在 AKS 集群中安装 ArgoCD
一旦集群启动并运行,您就可以在集群内部安装 ArgoCD。您将使用 ArgoCD 部署您的应用程序。
要安装该应用程序,请使用 Azure CLI。使用以下命令配置kubectl
连接到 AKS:
az aks get-credentials --resource-group NodeRG --name NodeCluster
要安装 ArgoCD,请使用以下命令:
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
ArgoCD 将安装在argocd
名称空间中。要获取命名空间中的所有资源,请输入:
kubectl get all --namespace argocd
公开 ArgoCD API 服务器
默认情况下,ArgoCD API 服务器不会向外部 IP 公开。因为在本教程中您将从 internet 访问应用程序,所以您需要通过服务类型负载平衡器向 ArgoCD 服务器提供外部 IP。
将 argocd-server 服务类型更改为 LoadBalancer:
kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "LoadBalancer"}}'
注意: 你也可以使用 Kubectl 端口转发来连接 API 服务器而不暴露服务。使用此命令:kubectl port-forward svc/argocd-server -n argocd 8080:443
您现在可以使用https://localhost:8080
访问 API 服务器。
访问 ArgoCD 门户网站
一旦您使用外部 IP 公开了 ArgoCD API 服务器,您现在就可以使用您生成的外部 IP 地址访问门户了。
ArgoCD 安装在argocd
名称空间中。使用此命令获取命名空间中的所有资源:
kubectl get all --namespace argocd
复制service/argocd-server
对应的External-IP
。
您可以在http://<EXTERNAL-IP>
访问应用程序。
对我来说,那是http://20.237.108.112/
要登录门户,您需要用户名和密码。用户名默认设置为admin
。
要获取密码,请执行以下命令:
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d; echo
使用此用户名/密码组合登录 ArgoCD 门户。
为 ArgoCD 配置 Kubernetes 清单
要配置 ArgoCD 在 Kubernetes 上部署您的应用程序,您必须设置 ArgoCD,使用 YAML 进行配置,以声明的方式连接 Git 存储库和 Kubernetes。
除此之外,您还可以从 Web 门户或使用 ArgoCD CLI 设置 ArgoCD。因为本教程遵循 GitOps 原则,所以我们使用 Git 库作为唯一的事实来源。因此,使用 YAML 文件的声明性方法效果最好。
ArgoCD 的关键特性和功能之一是通过手动或自动策略将应用程序部署到 Kubernetes 集群。
首先,在项目的根目录下创建一个名为argocd
的目录。在新目录下创建一个新文件,并将其命名为config.yaml
。
手动同步策略
使用此策略通过 CI/CD 管道手动同步应用程序。每当进行代码更改时,就会触发 CI/CD 管道,并调用 ArgoCD 服务器 API 来根据您将提交的更改启动同步过程。要与 ArgoCD 服务器 API 通信,您可以使用 ArgoCD CLI。您也可以使用适用于各种编程语言的 SDK 之一。
为 ArgoCD 设置手动同步策略,将其粘贴到config.yaml
:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: aks-nodejs-argocd
namespace: argocd
spec:
destination:
namespace: nodejs
server: "https://kubernetes.default.svc"
source:
path: manifests
repoURL: "https://github.com/Lucifergene/aks-nodejs-argocd"
targetRevision: circleci-project-setup
project: default
自动同步策略
ArgoCD 能够在检测到 Git 中所需清单与集群中实时状态之间的差异时,自动同步应用程序。
自动同步的一个好处是 CI/CD 管道不再需要直接访问 ArgoCD API 服务器来执行部署。取而代之的是,管道使用跟踪 Git repo 中的清单更改来提交和推送 Git 存储库。
如果要设置为自动同步策略,需要将其粘贴到config.yaml
中
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: aks-nodejs-argocd
namespace: argocd
spec:
destination:
namespace: nodejs
server: "https://kubernetes.default.svc"
source:
path: manifests
repoURL: "https://github.com/Lucifergene/aks-nodejs-argocd"
targetRevision: circleci-project-setup
project: default
syncPolicy:
automated:
prune: false
selfHeal: false
提交并将这些文件到您之前克隆的 GitHub 库的main
分支中。
创建持续集成管道
本教程的目的是展示如何通过 CircleCI 的持续集成 (CI)和 ArgoCD 的持续部署 (CD)在 Kubernetes 上部署应用程序。CI 管道应该触发构建容器的过程,将其推送到 Docker Hub,CD 应该在 Kubernetes 上部署应用程序。
要创建 CI 管道,您将使用与您的 GitHub 帐户集成的 CircleCI。CircleCI 配置名为config.yml
,位于项目根文件夹的.circleci
目录中。配置的路径是.circleci/config.yml
。
config.yml
的内容是:
version: 2.1
orbs:
docker: circleci/docker@2.1.1
azure-aks: circleci/azure-aks@0.3.0
kubernetes: circleci/kubernetes@1.3.0
jobs:
argocd-manual-sync:
docker:
- image: cimg/base:stable
parameters:
server:
description: |
Server IP of of ArgoCD
type: string
username:
description: |
Username for ArgoCD
type: string
password:
description: |
Password for ArgoCD
type: string
steps:
- run:
name: Install ArgoCD CLI
command: |
URL=https://<< parameters.server >>/download/argocd-linux-amd64
[ -w /usr/local/bin ] && SUDO="" || SUDO=sudo
$SUDO curl --insecure -sSL -o /usr/local/bin/argocd $URL
$SUDO chmod +x /usr/local/bin/argocd
- run:
name: ArgoCD CLI login
command: argocd login << parameters.server >> --insecure --username << parameters.username >> --password << parameters.password >>
- run:
name: Manual sync
command: argocd app sync $APP_NAME
- run:
name: Wait for application to reach a synced and healthy state
command: argocd app wait $APP_NAME
argocd-configure:
executor: azure-aks/default
parameters:
cluster-name:
description: |
Name of the AKS cluster
type: string
resource-group:
description: |
Resource group that the cluster is in
type: string
steps:
- checkout
- run:
name: Pull Updated code from repo
command: git pull origin $CIRCLE_BRANCH
- azure-aks/update-kubeconfig-with-credentials:
cluster-name: << parameters.cluster-name >>
install-kubectl: true
perform-login: true
resource-group: << parameters.resource-group >>
- kubernetes/create-or-update-resource:
resource-file-path: argocd/config.yaml
bump-docker-tag-kustomize:
docker:
- image: cimg/base:stable
steps:
- run:
name: Install kustomize
command: |
URL=https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize/v4.5.2/kustomize_v4.5.2_linux_amd64.tar.gz
curl -L $URL | tar zx
[ -w /usr/local/bin ] && SUDO="" || SUDO=sudo
$SUDO chmod +x ./kustomize
$SUDO mv ./kustomize /usr/local/bin
- checkout
- run:
name: Bump Docker Tag
command: |
cd manifests
kustomize edit set image $APP_NAME=$DOCKER_LOGIN/$APP_NAME:$CIRCLE_SHA1
- add_ssh_keys:
fingerprints:
- "$SSH_FINGERPRINT"
- run:
name: Commit & Push to GitHub
command: |
git config user.email "$GITHUB_EMAIL"
git config user.name "CircleCI User"
git checkout $CIRCLE_BRANCH
git add manifests/kustomization.yaml
git commit -am "Bumps docker tag [skip ci]"
git push origin $CIRCLE_BRANCH
workflows:
Deploy-App-on-AKS:
jobs:
- docker/publish:
image: $DOCKER_LOGIN/$APP_NAME
tag: $CIRCLE_SHA1,latest
- bump-docker-tag-kustomize:
requires:
- docker/publish
- argocd-configure:
cluster-name: $CLUSTER_NAME
resource-group: $RESOURCE_GROUP
requires:
- bump-docker-tag-kustomize
# Paste the following only when you opt for the ArgoCD manual-sync-policy:
- argocd-manual-sync:
server: $ARGOCD_SERVER
username: $ARGOCD_USERNAME
password: $ARGOCD_PASSWORD
requires:
- argocd-configure
CI 工作流由三个作业组成:
docker/publish
构建容器并将其推送到 Docker Hub。bump-docker-tag-kustomize
更新 Docker 图像标签并生成一个合并的 Kubernetes 配置文件。argocd-configure
在 AKS 集群上应用 ArgoCD 配置。argocd-manual-sync
仅当您选择手动同步策略时才需要。对于自动同步,您可以从文件中忽略该作业。
在这个工作流程中,我们广泛使用了 CircleCI orbs 。orb 是可参数化、可重用的配置元素的开源、可共享包,包括作业、命令和执行器。orb 已被直接使用或用于创建自定义作业。
提交并推送对 GitHub 库的更改。
在 CircleCI 建立项目
将应用程序部署到 AKS 的下一步是将 GitHub 存储库中的应用程序连接到 CircleCI。
进入你的 CircleCI 仪表盘,选择左边面板的项目选项卡。点击包含代码(aks-nodejs-argocd
)的 GitHub 库的设置项目按钮。
当提示选择您的 config.yml 文件时,单击最快选项并键入main
作为分支名称。CircleCI 会自动定位config.yml
文件。点击设置项目。
工作流将运行,但很快会显示一个Failed
的status
。这是因为您需要设置一个用户密钥并配置环境变量。
要设置用户密钥,请转到项目设置,然后在左侧面板中单击 SSH 密钥。在用户密钥部分,点击用 GitHub 授权。CircleCI 需要用户密钥,以便在工作流执行期间代表存储库所有者将更改推送到您的 GitHub 帐户。
要配置环境变量,点击环境变量。选择添加环境变量选项。在下一个屏幕上,键入环境变量和您想要分配给它的值。
文件中使用的环境变量有:
APP_NAME
:容器镜像名(aks-nodejs-argocd)ARGOCD_PASSWORD
: ArgoCD 门户密码ARGOCD_SERVER
: ArgoCD 服务器 IP 地址ARGOCD_USERNAME
: ArgoCD 门户用户名(管理员)AZURE_PASSWORD
: Azure 账号密码AZURE_USERNAME
: Azure 账号用户名CLUSTER_NAME
: AKS 集群名(NodeCluster)DOCKER_LOGIN
:坞站枢纽用户名DOCKER_PASSWORD
:坞站集线器密码GITHUB_EMAIL
: GitHub 账号邮箱RESOURCE_GROUP
: AKS 资源组(NodeRG)SSH_FINGERPRINT
:用于将更新的 Docker 标签推送到 GitHub 的用户密钥的 SSH 指纹
要定位 SSH 指纹,进入项目设置,从侧边栏选择 SSH 密钥。向下滚动到用户密钥部分并复制密钥。
重新运行工作流。这次status
会显示Success
。
您还会发现另一个将status
作为Not Run
的管道。这是因为您已经通过在提交消息中包含[skip ci]
明确指示 CircleCI 跳过管道。当 CircleCI 向 GitHub 提交更新后的配置文件时,[skip ci]
防止了工作流的自触发循环。
在 ArgoCD 仪表板上监控应用程序
当工作流重新运行时,显示Success
的status
表示应用程序已经部署在 AKS 集群上。
要观察和监视当前在 AKS 集群上运行的资源,请登录 ArgoCD 门户网站。
在本教程的前面部分,您学习了如何获取 ArgoCD 服务器 IP、用户名和密码以登录门户。登录后,您将进入应用程序页面。
单击应用程序名称。您将被重定向到一个页面,该页面包含 AKS 集群上运行的所有资源及其实时状态的树视图。
在 AKS 上访问应用程序
要访问该应用程序,您需要群集的外部 IP 地址。您可以使用 Azure CLI 来查找External-IP
。
使用以下命令配置kubectl
连接到 AKS:
az aks get-credentials --resource-group NodeRG --name NodeCluster
您在nodejs
名称空间中创建了所有的资源。要获取该命名空间中的所有资源,请使用以下命令:
kubectl get all --namespace nodejs
复制service/nodejs
对应的External-IP
。
您可以在http://<EXTERNAL-IP>
访问应用程序。我的情况,那就是http://20.121.253.220/
。
结论
在本教程中,您学习了如何在 Kubernetes 集群上使用 ArgoCD 按照 GitOps 实践连续部署您的应用程序。这包括配置自动化 CI 渠道。正确配置管道后,对应用程序代码的任何更改都会在应用程序 URL 上立即更新。告别在 Kubernetes 上手动配置和部署应用。
另外,您可以更改环境变量的值,以便为类似的应用程序使用 CircleCI 配置文件。
本教程的完整源代码也可以在 GitHub 上找到。
Avik Kundu 是 Red Hat 的一名软件工程师。他是全栈开发人员、开源贡献者和精通 DevOps 和云的技术内容创建者。他是 AWS 社区构建者和 Microsoft Learn 学生大使。他写过关于媒体、开发和 Opensource.com 的各种工具和技术的文章和教程。他喜欢学习新技术,并在公共场合分享他的知识。
将 Vue.js 应用程序自动部署到 Firebase | CircleCI
本教程涵盖:
- 在 Firebase 上设置 Vue.js 应用程序
- 使用 Firebase CLI 部署 Vue.js 应用程序
- 创建连续部署管道
快速搜索一下互联网,就会发现许多服务可以免费托管单页应用程序或静态网站。Firebase 就是这些服务之一。Firebase 是 Google 开发的一个开发平台,提供文件存储、托管、数据库、认证和分析。它是免费的,默认提供 SSL 证书,并在多个地区提供令人印象深刻的速度。在本教程中,我选择 Firebase 来托管我们的演示应用程序。
在本教程中,我将指导您使用 Firebase CLI 。您将使用它来部署现有的 Vue.js 应用程序,GitHub 上的是免费的。然后我们将超越手工部署,使用 CircleCI 建立一个连续部署管道。
先决条件
确保您正确设置了以下内容,以便遵循此要求:
对于本教程,您需要:
我们的教程是平台无关的,但是使用 CircleCI 作为例子。如果你没有 CircleCI 账号,请在 注册一个免费的 。
设置演示项目
首先将演示应用程序克隆到您计算机上的一个vue-firebase
文件夹中。输入以下命令:
git clone https://github.com/yemiwebby/vue-user-app.git vue-firebase
将目录更改到项目中。安装其所有依赖项,并使用以下方式为应用程序提供服务:
// change directory
cd vue-firebase
// install dependencies
npm install
// Run the application
npm run serve
转到http://localhost:3000
查看本地机器上的主页。
在本地运行单元测试
既然应用程序按预期运行,您需要确保为其组件编写的单元测试通过。打开新的终端。并输入以下命令:
npm run test:unit
以下是预期的输出:
> vue-user-app@0.1.0 test:unit
> vue-cli-service test:unit
PASS tests/unit/user.spec.js
User List component unit tests:
✓ renders props when passed (13 ms)
✓ Renders the list (6 ms)
✓ creates a user (7 ms)
Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 0.632 s
Ran all test suites.
就是这样!您的应用程序已在本地正确安装。下一步是为 Firebase 上的应用程序创建一个项目。在本教程的后面,您将使用 CircleCI 和 Firebase CLI 部署您的应用程序。
在 Firebase 上创建项目
如果您已经有一个 Firebase 帐户,您可以跳过这一步。
要创建一个帐户,进入 Firebase 主页,点击开始。您将被重定向到一个新页面,其中包含添加新项目的说明。
将项目添加到 Firebase
- 点击添加项目按钮。
- 输入项目的名称。我给我的取名为
vue-firebase
。 - 点击继续。
- 禁用谷歌分析;这个项目不需要它。
- 再次点击继续。
现在,您已经成功地在 Firebase 上创建了一个项目。接下来,您将把您的本地项目与 Firebase 帐户关联起来。
设置 Firebase 托管
为了在 Firebase 上成功地托管您的应用程序,您需要安装它的工具,并在您的项目中初始化它。
安装 Firebase CLI
打开新的终端。要全局安装 Firebase 工具,请运行以下命令:
npm install -g firebase-tools
您现在可以全局访问 Firebase 命令行界面工具。您可以使用它们将代码和资产部署到新创建的 Firebase 项目中。
将 Vue 连接到 Firebase
从终端登录到您的 Firebase 帐户:
firebase login
接下来,转到vue-firebase
项目的根目录。初始化项目:
firebase init
以下是如何回应提示:
- 选择托管:为 Firebase 托管配置文件,并(可选)设置 GitHub 操作部署。
- 使用现有项目:选择您之前创建的 Firebase 项目;我给我的取名
vue-firebase
。 - 输入
dist
作为公共目录。 - 配置为单页 app: 是。
- 使用 GitHub 设置自动构建和部署:否。对于本教程,我们使用 CircleCI 来运行测试和处理部署。
项目的初始化过程在项目的根目录下生成两个唯一的文件。这些文件是成功部署所必需的,并且必须签入源代码管理:
firebase.json
包含您项目的托管配置。其内容指导 Firebase CLI 更新和部署项目目录中的文件。.firebaserc
指定成功部署到 Firebase 后,连接到上传代码的项目。
配置 CircleCI
将.circleci/config.yml
的内容替换为:
version: 2.1
jobs:
build-and-test:
working_directory: ~/project
docker:
- image: cimg/node:17.4.0
steps:
- checkout
- run:
name: Update NPM
command: "sudo npm install -g npm"
- restore_cache:
key: dependency-cache-{{ checksum "package-lock.json" }}
- run:
name: Install Dependencies
command: npm install
- run: npm install --save-dev firebase-tools
- save_cache:
key: dependency-cache-{{ checksum "package-lock.json" }}
paths:
- ./node_modules
- run:
name: Run test for the application
command: npm run test:unit
- run:
name: Build application for production
command: npm run build
- run:
name: Deploy app to Firebase
command: ./node_modules/.bin/firebase deploy --token=$FIREBASE_TOKEN
workflows:
build-and-test:
jobs:
- build-and-test
这个脚本:
- 拉入 Node.js 的 CircleCI Docker 图像。
- 使用映像安装所有必需的依赖项。
- 在 CircleCI 上运行应用程序的测试。
- 使用
npm install --save-dev firebase-tools
安装 Firebase 工具。 - 设置一个命令,以便在测试成功时将应用程序部署到 Firebase。
部署需要FIREBASE_TOKEN
。因为您是从终端登录的,所以可以使用 Firebase CLI 轻松创建令牌。输入以下命令:
firebase login:ci
复制这些信息并保存在方便的地方。你以后会需要它的。
下一步是在 GitHub 上建立一个资源库,并将项目链接到 CircleCI。查看将项目推送到 GitHub 以获取指示。
登录您的 CircleCI 帐户。如果你注册了你的 GitHub 账户,你所有的库都可以在你项目的仪表盘上看到。
在您的vue-firebase
项目旁边,点击设置项目。
系统将提示您编写新的配置文件或使用现有的配置文件。选择现有的分支,并输入您的代码在 GitHub 上所在的分支的名称。点击设置项目。
您的第一个工作流将开始运行。这个构建将会失败,因为您还没有创建FIREBASE_TOKEN
环境变量。
要解决这个问题,您需要添加FIREBASE_TOKEN
作为环境变量。点击项目设置,然后点击左边栏的环境变量。创建此变量:
FIREBASE_TOKEN
是您之前从终端生成的令牌的值。
回到仪表板。点击从失败的重新运行工作流程。这会触发工作流,这次应该会成功构建。
转到上一步中显示的托管 URL。对我来说网址是:https://vue-firebase-2c246.web.app
。
结论
无论您使用 Firebase 还是其他托管服务,CircleCI 都可以帮助您实现 Vue.js 项目的持续集成和部署。我希望这对你有所帮助。本教程的完整源代码可以在 GitHub 上找到。
Oluyemi 是一名拥有电信工程背景的技术爱好者。出于对解决用户日常遇到的问题的浓厚兴趣,他冒险进入编程领域,并从那时起将他的问题解决技能用于构建 web 和移动软件。Oluyemi 是一名热衷于分享知识的全栈软件工程师,他在世界各地的几个博客上发表了大量技术文章和博客文章。作为技术专家,他的爱好包括尝试新的编程语言和框架。
使用 Shipa | CircleCI 从 CI 渠道向 Kubernetes 部署应用程序
原文:https://circleci.com/blog/deploying-apps-to-k8s-with-shipa/
Kubernetes 可以为开发组织带来一系列的优势。正确使用 Kubernetes 可以显著提高生产力,让您能够更好地利用您的云支出,并提高应用程序的稳定性和可靠性。另一方面,如果你没有很好地利用 Kubernetes,你的潜在好处就会变成缺点。作为一名开发人员,当您关注于快速交付高质量的代码时,这可能会变得非常令人沮丧。以对象为中心的应用程序架构的学习曲线和管理、脚本编写、集成到多个 CI 系统和管道中,以及管理基础架构都会降低您的工作效率。根据 Tidelift 和 New Stack 进行的调查,开发人员只有 32%的时间花在编写新代码或改进现有代码上。另外的 68%花费在会议、代码维护、测试、安全问题等等。
如果开发人员能够充分利用 Kubernetes 的优势,同时避免其缺陷,会怎么样?在本教程中,我们将展示 CircleCI 和 Shipa 如何共同帮助团队从 Kubernetes 中获得最佳表现。它是如何工作的?CircleCI 通过可定制的管道最大化速度,而 Shipa 则简化了 Kubernetes。这种结合让开发人员有更多的时间去做他们最擅长的事情:快速开发高质量的软件,而不改变他们的工作方式。您的平台工程团队可以管理、保护和交付一个强大的 Kubernetes 平台,使整个开发组织受益。
先决条件
对于本例,我们假设您有:
入门指南
在本教程中,我们将使用 CircleCI 和 Shipa orb 向 Kubernetes 集群交付我们的应用程序。orb是可重用的代码片段,有助于自动化重复的过程,加速项目设置,并使其易于与 Shipa 等第三方工具集成。
本教程的应用程序源代码可从这里获得。
在 CircleCI 上设置环境变量
为了让 CircleCI 成功地连接到 Shipa 并通过 CircleCI Shipa orb 交付应用程序代码,我们需要在 CircleCI 项目中设置这些环境变量:
- 这是您的应用程序的名称。在管道运行之前,按照以下说明在 Shipa 上创建应用程序:https://learn . Shipa . io/docs/application # creating-an-application
- SHIPA_CA 这是您用来连接到 SHIPA 目标实例的客户端证书。您可以通过运行以下命令检索您的证书:
cat ~/.shipa/certificates/<instance-name>/ca.crt | base64
-
SHIPA_USER 这是您用来登录 SHIPA 的用户名
-
SHIPA_PASSWORD 这是您用来登录 SHIPA 的密码
-
SHIPA_SERVER 这是 SHIPA 目标实例的地址。您可以通过运行以下命令来获取该地址:
shipa target list
要定义这些环境变量,请转到项目的设置页面。点击左侧栏中的环境变量,然后添加变量。
建立 Shipa
对于本教程,您需要在 Shipa 上创建一个应用程序。更多信息参见Shipa入门。
这里有一个如何在 Shipa 上设置我们的应用程序的快速示例。
首先,我们在 Shipa 上启用 Ruby 平台,这样我们的示例 Ruby 代码就可以部署了:
shipa platform add ruby
然后,我们创建将从 CircleCI 接收应用程序代码的应用程序:
shipa app create circleci ruby -t shipa-admin-team -o shipa-pool
我们在示例项目中使用的应用程序名称是circleci
,但是您可以给它起一个最适合您的名字。只要确保在SHIPA_APP_NAME
变量中传递正确的名称。
设置 CircleCI 管道
使用 CircleCI Shipa orb,我们将:
- 查看我们的应用程序代码
- 设置 Shipa
- 通过 Shipa 部署应用程序
对于 CircleCI 和 Shipa orb 来说,我们需要在名为.circleci
的文件夹中创建一个config.yml
文件。这是我们正在使用的config.yml
。
# Use the latest 2.1 version of CircleCI pipeline process engine. See: https://circleci.com/docs/configuration-reference/
version: 2.1
# Use a package of configuration called an orb.
orbs:
# Declare a dependency on the welcome-orb
shipa: shipa/orb@0.6.0
# Orchestrate or schedule a set of jobs
jobs:
shipa-deploy:
executor: shipa/default
steps:
- checkout
- shipa/install
- shipa/app-deploy
workflows:
# Name the workflow "welcome"
welcome:
# Run the welcome/run job in its own container
jobs:
- shipa-deploy
使用 Shipa 部署
现在我们需要运行 CircleCI 管道,并等待它完成。
管道完成后,我们的应用程序就成功部署了,并且可以从 Shipa CLI 通过在您的终端中键入以下命令来使用:
shipa app list
您还可以从 Shipa 仪表板上看到部署的应用程序。
从这里,开发者和运营商都可以访问与我们的circleci
应用相关的大量信息,包括:
- 日志
- 审计线索
- 网络策略
- CNAME 管理
- 监控信息
- 集成到事件管理工具中
- 应用程序依赖关系图
结论
使用 Shipa orb 与 CircleCI 集成,开发人员可以专注于应用程序代码,而开发人员和平台工程师可以专注于控件和护栏。
将 Clojure 应用程序部署到 Google Cloud - CircleCI
原文:https://circleci.com/blog/deploying-clojure-applications-to-google-cloud/
来自出版商的说明:您已经找到了我们的一些旧内容,这些内容可能已经过时和/或不正确。尝试在我们的文档或博客中搜索最新信息。
不断将 Clojure 应用部署到 Google 应用引擎
在 CircleCI 我们写了很多 Clojure。主要后端 app 是> 10 万行 Clojure 代码,前端是> 3 万行 ClojureScript。
我喜欢 Clojure 这种语言,以至于我决定也用 Clojure 做我的兼职项目。
当我意识到部署到 AWS 需要一系列精心设计的技巧来实现连续交付(在 GH -> production 上推送至 master)时,我感到非常惊讶。虽然我每天都在工作中使用 AWS,但我无法证明为我的副业项目构建自己的实现是正确的,比如秘密和蓝/绿部署。有 Kubernetes,但是目前只为我的副业项目运行 k8s 集群既不可行也不划算(开销太大)。当我在写一个 MVP 而没有时间做基础设施的时候,作为一个开发者,我需要的是在自制 CD 过程和 Kubernetes 的糟糕黑客之间找到一个很好的中间点。
我开始寻找能够让我开箱即用、配置尽可能少的 CD 的替代品。虽然 Heroku 是一个很好的选择,但我一直在寻找一种更灵活的,理想情况下负担得起的东西。
谷歌应用引擎,作为一个完全托管的应用运行时,目前符合我的标准。GAE 处理蓝/绿部署,允许比 Heroku 更多的定制。谷歌目前为每个决定创建新 GAE 账户的人提供 300 美元的信用点数,此外他们还提供免费等级。所有这些结合起来是一个很好的解决 MVP 的方法。
更改默认模板以支持应用引擎部署
我花了相当多的时间将我的第一个 Clojure 应用程序部署到 GAE,所以我想我应该创建一个框架项目,人们可以用它来将他们的第一个项目推出到 App Engine。我从一个全新的模板 Compojure 项目开始,只添加了一些东西。
-
Dockerfile。我们将使用 App Engine 灵活的环境,主要是因为更新总是意味着更好,Dockerfile 对于开始使用它是必不可少的。这个 Dockerfile 本身非常简单。它所做的只是从小型 Clojure 基础映像开始,将项目代码添加到
/code
并执行 entrypoint 脚本。理想情况下,我们会构建一个独立的 uberjar,只将放入容器中,但同样,这种设置的目的是为了方便实验。 -
拥有入口点脚本允许我们轻松定制启动我们正在构建的服务所需的命令。Compojure lein 模板提供了一种通过
lein ring server-headless
用应用程序启动无头服务器的便捷方式。其他框架或应用类型可能需要一个简单的lein run
来代替。 -
docker-compose . yml .docker-compose 文件纯粹是为了更好的开发体验。
docker-compose up -d
将为您启动并运行示例应用程序。 -
。circle ci/config . yml . circle ci 工作流的配置允许我们将测试步骤与部署分开。我们还使用两种不同的基本映像进行测试和部署——现在部署到 App Engine 只意味着推出代码,让 Google Cloud 为您完成其余工作,我们在部署时不需要 Clojure 映像。我们使用提供 Google Cloud SDK 的图片。
让我们来看一下将 Clojure 项目部署到 Google App Engine 所需的步骤。
将 Clojure 项目持续部署到 Google App Engine
我们假设你已经注册了一个谷歌云账户,并且收到了谷歌提供的免费积分。
1.建立一个谷歌云项目,并启用谷歌应用引擎灵活的环境
我们将导航到 console.cloud.google.com,登录或注册,然后创建一个新的谷歌云项目。
2.创建服务帐户并启用 GAE API 访问
为了给 CircleCI deploy build 权限来推出我们应用程序的新版本,我们需要在我们的项目中创建一个服务帐户。服务帐户将需要应用引擎管理和应用引擎灵活环境服务代理权限。创建服务帐户时,将生成的 JSON 保存到磁盘。
给服务账号添加必要的权限
一旦完成,我们将需要为我们的项目启用两个缺省禁用的 API 集。
在 Google Cloud 的项目控制面板中,我们可以导航到侧边栏中的 API 管理器项目,然后单击库,搜索这些项目并单击启用:
- Google 应用引擎管理 API
- 谷歌应用引擎灵活的环境
启用谷歌应用引擎管理 API
3.创建 CircleCI 项目并添加服务帐户凭据
我们已经将代码推送到我们的 VCS 提供商,所以现在我们导航到 CircleCI 项目页面,并从那里添加我们的 GitHub 或 Bitbucket repo 作为新的 CircleCI 2.0 项目。CircleCI 将运行一次build
任务,我们将看到我们的测试通过了。不会触发部署步骤。
现在,我们将下载的带有服务帐户的 JSON 添加到 CircleCI 项目的加密环境变量中。我们称这个变量为GCLOUD_KEY_JSON
。repo 中的配置会将该变量的内容输出到一个文件中,然后我们会将该文件传递给gcloud
实用程序进行身份验证。
将服务帐户凭证添加到 CircleCI 上的加密环境变量中
4.在 CircleCI 配置中编辑项目名称,然后推送
我们现在需要编辑 CircleCI 配置中的gcloud
调用中的项目名称,以匹配我们在 Google Cloud 上的项目名称。一旦我们提交并推动我们的更改,CircleCI 将运行完整的构建和部署工作流,并将部署我们的应用程序。
circle ci上的一次成功部署作业
从现在开始,在 GitHub 或 Bitbucket 上合并 pull 请求将同时触发构建和部署作业,并持续将我们的 Clojure 应用部署到 Google App Engine。
逮到你了
谷歌应用引擎中的一些东西可能会惹恼你,或者让你的谷歌云账单比你想象的要大得多。
首先,自动缩放在默认情况下是启用的。这就是为什么在 app.yaml 中我们选择手动缩放并指定实例类型。
其次,JVM 无法正确解释 Docker 守护进程设置的内存限制,无论您是在本地运行应用程序,还是在基于 Docker 的环境中运行应用程序,如 Google App Engine(或 CircleCI 2.0)。Java 8 不支持基于组的内存限制。当您在运行 Java 8 应用程序的 Docker 容器上设置内存限制时,您基本上是在告诉 Docker 守护进程,如果内存使用超过了限制,就终止容器,但是 JVM 并不知道这个限制。因此,它在运行它的机器上分配尽可能多的空闲内存(而不是容器)。这会导致一致的内存不足错误。解决方案是通过设置$JAVA_OPTS 环境变量来显式地限制 JVM 的内存使用,例如,如果您希望 JVM 只使用 300M 的内存,那么可以设置为包含-Xmx300m
。我们的 app.yaml 中指定的实例大小是最小的实例(也是最便宜的实例),并且只有 128MB 的可用内存。在模板项目中,我们将最大 Java 堆设置为 100MB。
结论
为 Clojure 项目设置从 CircleCI 到 Google App Engine 的连续部署需要几个步骤,但是过程本身非常简单。
对于我个人的使用案例——快速部署辅助项目——这种设置的最大优势是 App Engine 自动处理蓝/绿部署,因此对于较小的项目,不需要在部署前关闭应用程序,并在部署完成后再次启动它(当我部署到 AWS EC2 机器时,我必须在 CD 脚本中这样做)。不再需要手动部署,不再需要在 EC2 机器上不断打开 tmux 会话(真实的故事),也不再需要未部署的更改。
将基于容器的 web 应用部署到 Azure | CircleCI
原文:https://circleci.com/blog/deploying-container-based-node-apps-to-azure/
容器已经成为广泛使用的 DevOps 技术。容器使 DevOps 专业人员能够将基础设施定义为代码,从而可以为测试、部署和运行应用程序创建隔离的环境。在本文中,我们将学习如何使用 Azure 容器将 Node.js 应用程序部署到 Azure web 应用程序。
先决条件
要完成本教程,您需要:
安装并设置好所有这些之后,您就可以开始本教程了。
在 Azure 上创建容器注册中心
我们的第一步是在 Azure 上创建一个容器注册中心来存储和构建 Docker 容器。进入你的 Azure 门户主页,点击创建。然后从容器菜单中点击容器注册表。
在注册表创建页面上,填写信息,包括注册表的名称。
点击审核+创建打开审核页面。确认您的注册表信息,然后点击创建触发注册表创建过程。
如果您愿意,可以使用 Azure CLI 通过运行以下命令来创建注册表:
az acr create --name fikayoregistry --resource-group Demos-Group --sku standard --admin-enabled true
我已经将我的注册表命名为fikayoregistry
,但是您可能想要使用不同的名称。如果这样做,请确保用您选择的名称来代替。
克隆演示项目
下一步是使用 Docker 容器克隆 Node.js 项目以部署到 Azure。要克隆项目,请运行:
git clone --single-branch --branch base-project https://github.com/coderonfleek/node-azure-docker.git
接下来,使用cd node-azure-docker
进入项目的根目录,然后使用npm install
安装依赖项。
这个项目是一个基本的 Node.js API,它有一个端点用于返回一组todo
对象。它还包含一个用于测试端点的测试套件。
使用npm start
命令运行应用程序。应用程序将从地址http://localhost:5000
开始。在您的浏览器中加载以下路线http://localhost:5000/todos
,显示todos
列表。
在 Azure Container Registry 上创建和构建 Docker 映像
下一步是创建一个 Docker 文件,这样定制的 Docker 映像就可以运行该项目。然后,它将被推送到 Azure Container Registry (ACR)并在其上构建。
在项目的根目录下,创建一个新文件,将其命名为Dockerfile
(没有扩展名),并输入:
FROM node:current-alpine
COPY . /app
WORKDIR /app
RUN npm install
ENTRYPOINT ["npm", "start"]
这个文件使用一个标签为current-alpine
的node
图像作为它的基础。然后,它将项目的内容复制到映像中的一个app
文件夹中,将app
设置为工作目录,并运行npm
install 来安装依赖项。通过运行npm start
启动应用程序。
在项目的根目录下,使用Dockerfile
构建图像。确保用您之前选择的名称替换<container_registry_name>
。运行:
az acr build --registry <container_registry_name> --image mynodeimage .
注意命令末尾的点(.
)。确保包含它;它将构建上下文定义为当前目录。
这张图片被命名为mynodeimage
,它将出现在ACR
中。这个命令将文件夹的内容发送到 Azure Container Registry,它使用 Dockerfile 中的指令来构建图像并存储它。
若要查看您创建的映像,请转到门户中的 Azure 资源页面。单击您的注册表,然后从服务部分单击存储库。
有益的是,每个新建的图像都被标记为latest
。包含 Node.js 应用程序的 Docker 映像现在可以在您的注册表中部署到 Azure App Service。
在 ACR 上启用 Docker 访问
要部署应用程序,您需要在 Azure Container Registry 中启用 Docker 访问。这一步允许 Azure App 服务访问存储在注册表中的容器。
在您的资源页面中,单击注册表以打开其概述页面。从设置部分点击访问键。
确保管理员用户已启用。
当管理员用户选项启用时,按钮将变成蓝色,并显示用户名和一些密码。这些信息为 Azure web app 提供了对注册表中图像的访问。
创建 web 应用程序
接下来,创建一个 Azure Web App 。从 Azure 门户,通过点击主页,然后创建。选择 Web App 。
输入 web 应用程序名称,然后选择:
- Docker 容器作为发布选项
- Linux 作为操作系统
选择一个地区,然后点击下一步:Docker 。
在 Docker 页面上:
- 选择单个容器选项
- 选择 Azure 容器注册表作为图像源
- 在注册表字段中输入您的注册表名称(在本教程中我使用的是
fikayoregistry
) - 使用
mynodeimage
作为图像字段 - 对于标签,选择
latest
- 让
Startup Command
为空;您的 docker 文件已经有一个ENTRYPOINT
命令
现在我们准备好点击审查+创建来审查细节。然后点击创建。创建 web 应用程序后,使用浏览器访问地址https://[YOUR_WEB_APP_NAME].azurewebsites.net/todos
。请确保将YOUR_WEB_APP_NAME
替换为您创建的 web 应用程序的名称。我用的是https://nodeondocker.azurewebsites.net/todos
。
在您配置了 web 应用程序之后,Docker 映像将被提取并运行。你的应用第一次加载是“冷启动”。这意味着您的应用程序需要一些时间才能加载。每次从Docker
映像进行新的部署时,都会有一个“冷启动”。之后,该应用程序立即可用。
在 web 应用程序上实现持续部署
你不是来做一次性部署的,对吧?您需要持续部署。若要在 Azure 中进行设置,请转到您的资源页面,然后单击您的 web 应用名称以打开概述页面。从侧面菜单上的设置部分,通过点击容器设置。在容器设置页面,向下滚动到连续部署选项,打开,点击保存。
选择连续部署后,每当 Docker 映像在 Azure Container Registry 上重建时,web 应用程序将触发 Node.js 应用程序的新部署。
创建 CircleCI 项目
在转到 CircleCI 控制台之前,让我解释一下我们将使用容器建立到 web 应用程序的连续部署管道的策略。您已经知道,当在 Azure Container Registry 上构建或重建映像时,web 应用程序将重新部署新版本的应用程序。目标是以某种方式确保一旦代码被推送到远程存储库,就会触发新的构建。这些是我们将在本教程中使用的步骤:
- 使用 GitHub 存储库在 CircleCI 上创建一个项目
- 创建一个 Azure 容器注册任务。此任务监视远程存储库上的一个分支,以便在对该分支进行推送时重建映像
- 编写一个 CI/CD 管道脚本,当测试通过时,该脚本将推送到被监视的分支
我们将从在 CircleCI 建立项目开始。
首先,在项目的根目录下运行rm -rf .git
来删除任何现有的git
历史。接下来,将项目推送到 GitHub 上的远程存储库。确保这是连接到您的 CircleCI 帐户的 GitHub 帐户。
转到您的远程存储库并创建一个deploy
分支。
该分支将会被监视以触发对Docker
映像的重建。
在 CircleCI 仪表板上,点击添加项目。
点击设置项目。
在设置页面上,点击 Use Existing Config 以指示 CircleCI 您将手动添加一个配置文件,而不使用示例。将提示您下载管道的配置文件或开始构建。
点击开始建造。
注意: 这个构建将会失败,因为您还没有设置配置文件。我们将在本教程的后面部分进行介绍。
在 CircleCI 项目上设置 GitHub 身份验证
因为这个项目的deploy
分支将从管道配置中被推送,所以我们需要设置认证访问,以便 CircleCI 可以访问 GitHub 上的存储库。
幸运的是,CircleCI 提供了一种添加User API Key
来实现这一点的方法。从你的项目中,点击项目设置(页面右上角),然后点击 SSH 按键(在侧边菜单上)。
在用户密钥部分,点击用 GitHub 授权。如果你已经这样做了,选项将不可见,所以跳过下一段,在用户键块中复制指纹。
在连接到 GitHub 之后,一个添加用户密钥按钮出现在用户 API 密钥部分。单击此按钮以生成指纹,我们将在本教程稍后的部署管道中使用该指纹。复制指纹并保存在安全的地方。
因为指纹将与您的 GitHub 电子邮件和用户名一起在管道脚本中使用,所以将这些凭证放在环境变量中更安全。从项目设置的侧菜单中,点击环境变量。添加这些环境变量:
GITHUB_EMAIL
:您连接的 GitHub 账户的电子邮件GITHUB_USERNAME
:你的 GitHub 用户名GITHUB_FINGERPRINT
:生成的认证指纹
创建 Azure 容器存储库任务
我之前提到过,我们需要一个 Azure Container Repository 任务来监视deploy
分支的更新和触发重建。不过,首先,我们需要一个 GitHub 个人访问令牌。
从你的 GitHub 页面,点击设置、开发者设置。从侧面菜单中,选择个人访问令牌。然后,点击生成新令牌。确认您的密码以进入令牌创建页面。
输入密钥的描述。授予除delete_repo
之外的所有权限。对于本教程,最重要的权限是在 repo 中创建一个webhook
的能力。我们将使用这个 webhook 向 Azure 容器注册中心发送信号,以触发Docker
图像的新构建。
点击生成令牌并在令牌显示时复制令牌。该令牌将不会再次显示,因此请确保您现在获得信息。
要创建 Azure 容器注册表任务,请转到项目的根目录。使用您的存储库地址、注册表名称和 GitHub 访问令牌,运行:
az acr task create --registry <container_registry_name> --name buildnodeapp --image mynodeimage --context <your_github_repo>#deploy --file Dockerfile --git-access-token <access_token>
这段代码创建了一个buildnodeapp
任务,它将在每次更新被推送到deploy
分支时重建mynodeimage
映像。要查看您新创建的任务,请转到注册页面并点击任务。
编写持续部署脚本
我们的下一步是使用Docker
容器为 Node.js 应用到 Azure web 应用的持续部署编写管道脚本。为了使管道脚本能够将更新推送到 GitHub repo 的deploy
分支,我们将使用节点包 gh-pages 。大多数情况下,这个包用于将文件推送到一个专门的gh-pages
分支,以将静态站点部署到 GitHub 页面。方便的是,这个包是可配置的,因此您可以将文件从一个分支推到任何一个存储库中的另一个分支。
在项目的根目录下,安装gh-pages
包作为开发依赖项:
npm install gh-pages --save-dev
接下来,在package.json
文件中添加deploy
脚本:
"scripts" : {
...
"deploy" : "npx gh-pages -b deploy --message '[skip ci] Updates' -d ./"
}
这个脚本调用gh-pages
,使用npx
将文件从main
分支推送到deploy
分支。我添加了[skip ci] Updates
的--message
参数,这样当更改被推送到这个分支时,CircleCI 就不会重新运行管道。
在项目的根目录下,创建一个名为.circleci
的文件夹,并在其中创建一个名为config.yml
的文件。在config.yml
里面,输入:
version: 2
jobs:
build:
working_directory: ~/repo
docker:
- image: circleci/node:10.16.3
steps:
- checkout
- run:
name: update-npm
command: "sudo npm install -g npm@5"
- restore_cache:
key: dependency-cache-{{ checksum "package-lock.json" }}
- run:
name: install-packages
command: npm install
- save_cache:
key: dependency-cache-{{ checksum "package-lock.json" }}
paths:
- ./node_modules
- run:
name: Run tests
command: npm run test
deploy:
working_directory: ~/repo
docker:
- image: circleci/node:10.16.3
steps:
- checkout
- run:
name: Configure Github credentials
command: |
git config user.email $GITHUB_EMAIL
git config user.name $GITHUB_USERNAME
- add_ssh_keys:
fingerprints:
- $GITHUB_FINGERPRINT
- run:
name: Deploy to Azure Web App Using Azure Container Registry Task
command: npm run deploy
workflows:
version: 2
build:
jobs:
- build
- deploy:
requires:
- build # only deploy once build job has completed
filters:
branches:
only: main # only deploy on the main branch
该文件定义了一个包含两个任务的工作流:build
和deploy
。
build
作业从远程存储库中检出代码,安装依赖项,并运行测试以确保代码中没有错误。一旦build
作业完成,deploy
作业就会接管。它检查出代码的一个干净的副本,因为我们不想将node_modules
文件夹从先前的作业推到被监视的分支。然后deploy
作业配置对 GitHub 的访问,这样管道脚本就可以将更新推送到被监视的分支。然后,该作业运行 Node.js 脚本来推送更新并触发新的Docker
映像构建。
deploy
作业依赖于build
作业,因此在build
作业完成之前它不会运行。为了查看运行两个作业后部署的变化,我们需要向todo.js
添加一个任务:
module.exports = [
...
{
id: 4,
task: "Make Dinner"
}
];
添加任务意味着我们需要更新__tests__/apiTest.js
中的测试套件来检查四个todo
对象。将第 15 行改为:
expect(res.body.length).toBe(4);
保存对项目的更改,并提交到远程存储库中的主分支。
点击deploy
作业查看详情:
如果你在你的注册页面上点击buildnodeapp
并点击运行标签,你会发现一个新构建的Docker
映像正在运行(cj2
)。
现在转到您的浏览器,在那里之前加载了/todos
端点。当你重新加载页面时,你会发现一个新的todo
对象。
结论
容器为应用程序开发人员和 DevOps 架构师提供了弥合开发和生产环境之间的差距的能力,这种差距可能会导致错误或应用程序无法按预期运行。在本教程中,我们展示了如何使用容器无缝部署 Azure web 应用。我希望你能用你所学到的来改进你自己的应用。
编码快乐!
Fikayo Adepoju 是 LinkedIn Learning(Lynda.com)的作者、全栈开发人员、技术作者和技术内容创建者,精通 Web 和移动技术以及 DevOps,拥有 10 多年开发可扩展分布式应用程序的经验。他为 CircleCI、Twilio、Auth0 和 New Stack 博客撰写了 40 多篇文章,并且在他的个人媒体页面上,他喜欢与尽可能多的从中受益的开发人员分享他的知识。你也可以在 Udemy 上查看他的视频课程。
使用 CI | CircleCI 将文档部署到 GitHub 页面
原文:https://circleci.com/blog/deploying-documentation-to-github-pages-with-continuous-integration/
持续集成 (CI)工具一直朝着灵活的通用计算环境发展。它们不仅用于运行测试和报告结果,还经常运行完整的构建并将工件发送到外部系统。如果您已经依赖于 CI 系统来满足这些需求,那么使用相同的平台来构建和部署您的文档可能会更方便,而不是引入额外的工具或服务。
这篇文章在深入研究使用 CircleCI 将文档部署到 GitHub 页面的细节之前,概述了当前可用于构建和部署文档的一些流行选项,对于已经使用这些工具来托管代码和运行自动化测试的团队来说,这是一个非常方便的工作流。
部署文档的选项
API 文档通常使用特定于语言的文档工具(Python 的sphinx
、Java 的javadoc
等)从代码库呈现。).文档的构建可以在开发人员的本地机器上、在 CI 环境中或者在特定于文档的托管服务中完成。
托管文档的服务通常是特定于语言的,对于倾向于用单一语言编写项目的团队来说,这是一个非常好的低摩擦选择。例如,阅读文档多年来一直是 Python 社区的标准工具。read Docs 使用 webhooks 来监视对托管存储库的提交,并将为每次代码更新自动构建和呈现文档,并提供一些在您自己的管道中难以复制的便利,例如部署多个版本的文档和维护从呈现的文档到源代码的链接。如果团队需要为其他语言部署文档,或者构建需要不常见的系统依赖,而这些系统依赖又不能通过pip
或conda
包管理器安装,那么它的局限性就会显现出来。使用特定于文档的服务还意味着为该附加服务维护另一组用户帐户和权限。
相反,构建文档最不依赖于基础设施的工作流是开发人员在本地构建文档,并将结果签入项目存储库。大多数团队更喜欢将生成的内容放在源代码控制之外,以使代码审查更简单,并减轻开发人员构建和提交内容的责任,但有些团队可能喜欢在代码旁边查看文档的修订历史。GitHub 通过提供将docs
目录的内容呈现到 GitHub 页面的选项,开发了对该工作流的支持。对于 CI 系统中的文档,其他设置可能仍然需要单独的部署步骤。
相反,如果一个团队决定将文档作为 CI 流程的一部分来构建,那么内容可以被部署到各种各样的目的地,比如本地维护的服务器、像亚马逊 S3 这样的对象存储、GitHub Pages 或者其他一些外部托管服务。在大多数情况下,CI 作业需要某种形式的凭据,以便向目标进行身份验证,这可能是流程中最复杂的部分。GitHub Pages 作为文档宿主的主要优势之一是权限的合并;任何对存储库拥有管理员权限的开发人员都可以设置 GitHub 页面的部署,并提供 CI 服务提交内容所需的部署密钥。
部署到 GitHub 页面的选项
GitHub 为将站点部署到 GitHub 页面提供了三个选项,对于工作流和凭证有不同的含义。
最古老的选项,也是我们将在演练中使用的选项,是推送到一个特殊的gh-pages
分支来触发部署。这通常被维护为一个“孤儿”分支,与master
的修订历史完全分离,这可能有点难以维护。在我们的例子中,我们将构建一个 CircleCI 工作流,该工作流构建文档,使用库提交对gh-pages
分支的更改,然后使用我们将提供的部署密钥将分支推送到 GitHub。
第二种选择是让 GitHub 页面呈现master
分支。这对于仅用于存放文档的存储库很有用,但是如果您的目标是通过将代码和呈现的文档紧密地放在一个单一的权限模型中来获益,这就没什么帮助了。
最后,GitHub Pages 可以在master
分支上呈现一个docs
目录,该目录支持开发人员生成和提交文档作为其本地工作流一部分的工作流。这不需要 CI 平台,也不需要额外的凭证,但是大多数团队不喜欢将生成的内容包含在他们的master
分支中,如前一节所讨论的。
逐步演练
创建基本 Python 项目
让我们构建一个小的 Python 包,它使用标准的 Python 生态系统工具进行测试(pytest
)和文档记录(sphinx
)。我们将配置 CircleCI 来运行测试、构建文档,并最终通过gh-pages
分支部署到 GitHub 页面。该项目的完整代码可在 jklukas/docs-on-gh-pages 获得。
在一个新的目录中,我们将创建一个名为mylib
的简单包,其中只有一个hello
函数。mylib/__init__.py
长相:
def hello():
return 'Hello'
我们还需要用一个空的__init__.py
文件和包含以下内容的test_hello.py
创建一个test
目录:
import mylib
def test_hello():
assert mylib.hello() == 'Hello'
为了实际运行测试,我们需要安装pytest
,所以让我们在一个requirements.txt
文件中指定它。我们还将请求sphinx
,这是我们将在下一节使用的文档工具:
sphinx==1.8.1
pytest==3.10.0
此时,我们可以编写一个非常简单的 CircleCI 工作流,其中包含一个运行测试的作业。我们创建一个看起来像这样的.circleci/config
:
version: 2
jobs:
test:
docker:
- image: python:3.7
steps:
- checkout
- run:
name: Install dependencies
command: pip install -r requirements.txt
- run:
name: Test
command: pytest
workflows:
version: 2
build:
jobs:
- test
我们提交所有这些结果,将它们推到一个新的 GitHub 存储库中,并在 CircleCI 中启用该存储库。CircleCI 应该为应该返回绿色的master
分支生成一个初始构建。
添加文档
现在我们有了一个包含测试的基本库,让我们来建立文档框架。此时,您需要在本地安装sphinx
,因此您可能希望使用venv
工具创建一个虚拟环境,然后调用pip install -r requirements.txt
,这使得sphinx-quickstart
命令行工具可用于生成文档框架。我们将像这样调用它:
sphinx-quickstart docs/ --project 'mylib' --author 'J. Doe'
# accept defaults at all the interactive prompts
sphinx-quickstart
为我们生成了一个Makefile
,所以构建文档就像从docs/
目录中调用make html
一样简单。让我们在 CircleCI 流程中的一项新工作中对其进行整理。我们可以在jobs:
下面添加以下内容
docs-build:
docker:
- image: python:3.7
steps:
- checkout
- run:
name: Install dependencies
command: pip install -r requirements.txt
- run:
name: Build docs
command: cd docs/ && make html
- persist_to_workspace:
root: docs/_build
paths: html
调用make html
会填充一个包含我们想要部署的内容的docs/_build/html
目录。我们新的docs-build
作业的最后一个persist_to_workspace
步骤将该目录的内容保存到一个中间位置,我们工作流中的后续作业可以访问该位置。现在,我们将把这个新任务添加到我们的工作流中:
workflows:
version: 2
build:
jobs:
- test
- docs-build
并提交结果。
即使没有部署呈现的内容,这项工作现在也可以检查我们文档的完整性。如果sphinx
无法成功运行,该作业将失败,让您知道有问题。
将呈现的文档部署到 gh-pages 分支
此时,我们已经准备好开始构建 CI 工作流的最后一部分,这项工作将通过将构建的文档推送到我们存储库的gh-pages
分支来部署它。
我们希望gh-pages
成为一个“孤儿”分支,它只跟踪已呈现的文档,并且在master
中有一个独立于源代码的时间线。可以创建这样一个分支,并使用简单的git
命令行调用将内容复制到其中,但是它可能充满了边缘情况,如果出现任何问题,很容易导致工作环境损坏。在这种情况下,引入一个专门构建的工具是一个合理的选择,有几个开源项目可以使用。目前其中最流行的实际上是一个名为gh-pages
的 Node.js 模块,它包括一个命令行界面,这就是我们在这里要使用的。
您完全有理由质疑我们为什么选择一个需要 JavaScript 环境来部署 Python 文档的应用程序。乍一看,这似乎增加了复杂性,但它实际上非常无缝地融入了我们的工作流,因为我们的 CI 环境本身支持 Docker 容器,我们可以为每个作业选择独立的基本映像。我们用 Python 运行时在容器中构建文档,然后用 Node.js 运行时在新容器中共享输出。
让我们继续在我们的config.yml
文件的jobs
部分下面编写第一个版本的docs-deploy
作业,并逐步完成以下步骤:
docs-deploy:
docker:
- image: node:8.10.0
steps:
- checkout
- attach_workspace:
at: docs/_build
- run:
name: Install and configure dependencies
command: |
npm install -g --silent gh-pages@2.0.1
git config user.email "ci-build@klukas.net"
git config user.name "ci-build"
- run:
name: Deploy docs to gh-pages branch
command: gh-pages --dist docs/_build/html
我们使用一个node
基础映像,这样npm
包管理器和 Node.js 运行时就可用了。attach_workspace
步骤将来自docs-build
步骤的渲染文档装载到我们的容器中,然后我们调用npm install
来下载目标模块,其中包括一个命令行实用程序gh-pages
,我们将在下一步中调用它。模块文档中要求使用git config
命令。最后,gh-pages --dist docs/_build/html
的调用将html
目录的内容复制到gh-pages
分支的根,并将结果推送到 GitHub。
让我们将这个新步骤添加到我们的工作流程中。workflows
部分现在看起来像这样:
workflows:
version: 2
build:
jobs:
- test
- docs-build
- docs-deploy:
requires:
- test
- docs-build
filters:
branches:
only: master
我们使docs-deploy
作业依赖于另外两个步骤,这意味着在这两个步骤成功完成之前,它不会运行。这确保我们不会意外地发布没有通过测试的存储库状态的文档。我们还设置了一个过滤器,指定除了构建master
分支之外,应该跳过docs-deploy
作业。这样,我们就不会因为其他分支上仍在进行的变更而覆盖已发布的文档。
如果我们签入所有这些更改并让 CircleCI 运行我们的作业,我们的新作业将会失败:
错误:您用来验证的密钥已被标记为只读。
因此,我们需要做更多的工作来清理这些问题,并确保我们的 CI 工作拥有必要的证书。
提供部署密钥
正如在https://circleci.com/docs/gh-bb-integration/中所讨论的,GitHub 提供了几个选项来给一个任务改变一个库的访问权。一般来说,GitHub 权限是与用户绑定的,所以一个凭证要么必须绑定到一个人类用户帐户,要么必须提供一个特殊的机器用户帐户。在跨存储库授予访问权限方面有很大的灵活性,但这可能会变得有些复杂。
我们选择提供一个读/写部署密钥。这是一个特定于单个存储库而非用户的 ssh 密钥对。这对团队来说很好,因为这意味着如果提供密钥的用户离开组织或删除他们的帐户,访问权不会消失。这也意味着,作为帐户管理员的任何用户都可以按照下面的步骤进行集成设置。
让我们遵循 CircleCI 文档中的说明,并将它们应用到我们的案例中。
我们首先在本地机器上创建一个 ssh 密钥对:
ssh-keygen -t rsa -b 4096 -C "ci-build@klukas.net"
# Accept the default of no password for the key (This is a special case!)
# Choose a destination such as 'docs_deploy_key_rsa'
我们最终得到一个私钥docs_deploy_key_rsa
和一个公钥docs_deploy_key_rsa.pub
。我们将私钥交给 CircleCI,方法是导航到 https://circleci.com/gh/jklukas/docs-on-gh-pages/edit#ssh 的,点击“添加 SSH 密钥”,输入“github.com”作为主机名,然后粘贴私钥文件的内容。此时,我们可以继续从系统中删除私钥,因为只有我们的 CircleCI 项目应该可以访问:
rm docs_deploy_key_rsa
https://circleci.com/gh/jklukas/docs-on-gh-pages/edit#ssh页面将向我们展示密钥的指纹,这是一个可以安全公开的唯一标识符(不像私钥本身,它足以让攻击者对您的存储库进行写访问)。我们在我们的docs-deploy
作业中添加了一个步骤,以授予作业对具有该指纹的键的访问权:
- add_ssh_keys:
fingerprints:
- "59:ad:fd:64:71:eb:81:01:6a:d7:1a:c9:0c:19:39:af"
当我们谈到安全问题时,我们将前往https://circle ci . com/GH/jklukas/docs-on-GH-pages/edit # advanced-settings并仔细检查“将秘密从分叉的 pull 请求传递到构建”是否设置为默认值“Off”。SSH 密钥是一种我们只希望在信任正在运行的代码时才公开的秘密;如果我们允许 forks 使用这个密钥,攻击者就可以创建一个 pull 请求,将我们的私钥内容打印到 CircleCI 日志中。
现在,我们需要将公钥上传到 GitHub,以便它知道信任来自 CircleCI 的用我们的私钥发起的连接。我们前往>添加部署密钥,将其标题设为“CircleCI write key”并粘贴到docs_deploy_key_rsa.pub
的内容中。如果您还没有删除私钥,请格外小心,不要意外地从docs_deploy_key_rsa
复制!
一些最终修正
在我们测试 CircleCI 工作流能否成功地将更改推送到 GitHub 之前,让我们解决一些最后的细节问题。
首先,我们构建的文档包含以_
开头的目录,这些目录对jekyll
有特殊的意义,它是 GitHub 页面中内置的静态站点引擎。我们不希望 jekyll 更改我们的内容,所以我们需要添加一个.nojekyll
文件并将--dotfiles
标志传递给gh-pages
,因为否则该实用程序将忽略所有的点文件。
其次,我们需要提供一个包含[skip ci]
的定制提交消息,该消息指示 CircleCI 当我们将该内容推送到gh-pages
分支时不应该重新启动。gh-pages
分支只包含渲染的 HTML 内容,而不包含源代码和config.yml
,所以构建将没有任何关系,只会在 CircleCI 中显示为失败。我们的全部工作现在看起来像:
docs-deploy:
docker:
- image: node:8.10.0
steps:
- checkout
- attach_workspace:
at: docs/_build
- run:
name: Disable jekyll builds
command: touch docs/_build/html/.nojekyll
- run:
name: Install and configure dependencies
command: |
npm install -g --silent gh-pages@2.0.1
git config user.email "ci-build@klukas.net"
git config user.name "ci-build"
- add_ssh_keys:
fingerprints:
- "59:ad:fd:64:71:eb:81:01:6a:d7:1a:c9:0c:19:39:af"
- run:
name: Deploy docs to gh-pages branch
command: gh-pages --dotfiles --message "[skip ci] Updates" --dist docs/_build/html
我们准备提交更新后的配置,让 CircleCI 运行工作流。一旦它显示为绿色,我们应该注意到我们的存储库现在有了一个gh-pages
分支,并且呈现的内容现在可以在https://jklukas.github.io/docs-on-gh-pages/获得。
结论
没有一种明显的“最佳方式”来构建和部署文档。对您的团队来说,阻力最小的路径将取决于您已经熟悉的工作流、工具和基础设施的特定组合。您的组织结构也很重要,因为它将影响到谁需要参与提供凭证并使系统相互通信。
这里介绍的特定解决方案目前非常适合 Mozilla 的数据平台团队(参见实践中的一个例子,位于Mozilla/python _ moz telemetry),因为它适用于不同的语言(我们的团队也维护 Java 和 Scala 中的项目),它最大限度地减少了需要熟悉的工具的数量(我们已经投资了 GitHub 和 CircleCI),权限模型让我们的团队在设置和控制文档工作流方面拥有自主权,并且我们还没有发现需要特定于文档的托管提供商提供的任何更高级的功能。
杰夫·克鲁卡斯有实验粒子物理学的背景,他既是教师又是帮助发现希格斯玻色子的研究人员。他现在在俄亥俄州哥伦布市的 Mozilla 公司的 Firefox 数据平台上远程工作,之前是 Simple 公司数据平台的技术负责人,Simple 是一家云端无分支银行。
使用 GCP | CircleCI 部署您的 Gradle Build 缓存节点
原文:https://circleci.com/blog/deploying-gradle-build-cache-node-to-gcp/
本教程是使用构建缓存对你的 Android Gradle 构建进行涡轮增压的后续。
这篇文章的重点是远程构建缓存,这是一种构建速度加速技术,可以在本地和 CI 构建中实现。这是一项值得了解的技术,因为:
- 如果没有缓存系统,每个构建都是一个全新的、干净的构建,因此整个项目都是从头开始构建的,即使是很小的更改。
Gradle 提供了一个构建缓存节点作为 Docker 映像。您可以通过多种方式托管此映像。在本教程中,我将带领你在免费工具 GCP (Google Cloud Platform)上建立一个构建缓存节点的步骤。
先决条件
要遵循本教程,需要做一些事情:
- 对 Gradle 构建工具的基本理解
- 了解如何在 CircleCI 上建立一个 Android 项目
- 了解 Android 构建流程
- 关于 GCP 虚拟机(VM)实例、防火墙及其工作原理的基本知识
创建并访问您的 Google 控制台帐户
首先,您需要创建或访问您的谷歌云平台账户。
注意: 如果您是第一次设置您的主机,请同意服务条款,然后单击同意并继续按钮。
要访问 GCP 的免费产品,请从导航菜单中选择入门选项。然后点击免费入门按钮。
首先验证您的帐户信息。
接下来,输入有效的电话号码。谷歌将向您发送确认文本。完成验证后,点击继续按钮。
尽管下一步要求您输入付款信息,但除非您打开自动计费,否则不会向您收费。
成功完成验证过程后,您会看到一条确认消息。点击得到它继续。
现在,您已经设置了控制台以使用免费层产品,您可以继续构建缓存节点设置。
设置构建缓存节点
在 GCP 实例上,构建缓存节点的过程分为两部分:
- 在 VPC 网络部分下创建防火墙规则
- 在计算引擎部分创建一个虚拟机实例
通过利用构建缓存节点用户手册并为 GCP 添加一些定制配置,您可以设置您的构建缓存节点。
配置虚拟私有云(VPC)网络
VPC 网络是物理网络的虚拟版本,在谷歌的生产网络内部实现。它做了很多事情,但最重要的是它为您的计算引擎虚拟机(VM)实例提供连接。这一点很重要,因为默认情况下,来自网络外部的传入流量会被阻止。这意味着我们需要创建一个防火墙规则来控制到构建缓存节点 VM 实例的传入或传出流量。
创建防火墙规则
在 Google 控制台仪表板上,导航至:Networking > VPC Network > Firewall
。如果系统提示,请单击启用以启用计算引擎。然后,点击创建防火墙规则按钮。
输入防火墙规则详细信息:
- 在名称字段中,输入
gradle-firewall-rule
- 在描述字段中,输入
Ingress firewall rule for the Gradle build cache node
- 将目标标记指定为 gradle-build-cache-node-tag
- 输入
0.0.0.0/0 192.168.2.0/24
作为源 IP 范围 - 将协议和端口指定为
tcp: 5071
输入详细信息后,点击创建按钮。
</blog/media/2021-08-27-gradle-cache-10.mp4>
设置 GCP 以启动虚拟机
谷歌计算引擎(GCE)是谷歌云平台(GCP)的基础设施即服务(IaaS)组件。GCP 建立在运行谷歌搜索引擎、Gmail、YouTube 和其他服务的全球基础设施之上。谷歌计算引擎使用户能够按需启动虚拟机。
要创建 VM 实例,请转到 Google Cloud 控制台仪表板,导航到Compute > Compute Engine > VM instances
,然后单击创建实例按钮。
输入虚拟机实例详细信息:
- 在名称字段中,输入
gradle-build-cache-node
。 - 选择
Europe-north1 (Finland)
作为区域。选择一个离你和你的开发团队近的。 - 选择
europe-north1-a
作为区域。 - 对于机器配置,输入
N1
表示系列。 - 为机器类型输入
n1-standard-1
(1 个 vCPU,3.75 GB 内存)。
接下来,选择Deploy a container image to this VM instance
。在容器图像字段中,输入gradle/build-cache-node
。
我们还需要设置一个磁盘卷供我们的构建缓存使用。展开高级容器选项,点击添加卷。然后添加这些参数:
- 对于卷类型,添加
Directory
。 - 对于挂载路径,添加
/data
。 - 对于主机路径,添加
/home/build-cache
。 - 选择
Read/write
模式。
完成防火墙配置
您的下一个任务是添加标记和防火墙规则,以允许来自互联网的特定网络流量。展开管理、安全、磁盘、网络、单独租赁部分,并选择网络选项卡。然后添加我们之前创建的防火墙规则:
gradle-build-cache-node-tag
点击创建并等待您的新虚拟机启动。
使用虚拟机访问缓存节点
要通过 VM 实例的外部 IP 访问缓存节点,请将:5071
附加到外部 IP 地址的末尾。你可以在谷歌控制台上找到外部 IP 地址。
注意: 如果你得到一条消息,说网站不能提供安全连接,请通过 HTTP 而不是 HTTPS 访问 IP。
为生成缓存配置访问控制
下一步很重要,因为我们正在实现 UI 授权安全检查。默认情况下,内置缓存节点允许任何用户在缓存中存储和检索条目。这并不理想,因为未经授权的用户可以存储、检索和删除缓存条目。唯一允许对构建缓存节点进行更改的系统是您的 CI 服务器,使它成为您的唯一真实的来源。
要改变这一点,折叠构建缓存下的设置部分。点击添加用户,给新用户一个用户名,密码,访问级别Read & write
。读&写访问允许存储工件。 (notes) 字段不是必需的,但是如果不同的场景有多个用户,它会很有帮助。
一旦用户被添加到系统中,就可以将匿名访问限制为None
不允许访问或Read
只读访问。
点击保存保存凭证和权限。
推荐的方法是创建一个具有Read & write
访问权限的用户,并将匿名访问权限仅限于Read
。CI 构建然后作为用户进行身份验证并写入缓存,而开发人员匿名连接并仅从缓存中读取。
注意 : 如果你试图访问缓存节点,而你没有得到授权,你会得到一个response status 401: Unauthorized
错误。
Android 项目上的缓存访问控制
您可以配置 HttpBuildCache 用来访问构建缓存服务器的凭证,如settings.gradle
文件所示。
buildCache {
remote(HttpBuildCache) {
url = 'https://example.com:8123/cache/'
credentials {
username = 'build-cache-user'
password = 'C0mplic@ted-pa$$worD'
}
}
}
运行 CI 构建以验证正常工作的缓存节点
现在,我们需要确保 Gradle 构建缓存按预期工作。将您对settings.gradle
文件所做的更改推送到 GitHub 存储库中。该推送触发 CI 构建。
一旦构建成功完成,就会有一些工件存储在构建缓存中,如 UI 仪表板上所示。
结论
在本教程中,您已经学习了如何使用 GCP 虚拟机实例创建和运行 Gradle build 缓存节点。你更新了你的应用,并将其缓存推送给它。您现在已经有了使用构建速度加速技术的经验,您可以将它用于您的本地和 CI 构建。有了缓存系统,您不再需要从头开始运行整个项目。这为您的团队节省了时间和资源,并让您可以更频繁地进行更小的修复和更新,因此您可以更快地添加功能和修复错误。
Taracha 是一个创造者,他的使命是帮助公司用最简单的方式解决复杂的问题。他关心的是找到他热爱的愿景和事业,并利用技术帮助这些公司解决他们的挑战。
他有超过 6 年的本地移动应用程序开发经验和 4 年的 web 应用程序开发经验。
他目前是 Premise Data 的高级软件工程师,负责新产品功能的开发和部署,并对开发人员生产力工程领域充满热情。
从 CircleCI 部署到 Linode 和其他 VPS 提供商- CircleCI
原文:https://circleci.com/blog/deploying-to-linode-vps-providers/
构建和测试软件的最终目标通常是部署该软件。CircleCI 官方博客和许多社区博客展示了部署到 Kubernetes 集群、推送 Docker 注册中心、上传到 AWS S3,甚至新的无服务器技术的例子。然而,对于个人开发者甚至小公司来说,使用这样的大型部署平台并不总是可行的。
但是还有其他选择。
在这篇博文中,我们将介绍几种将软件部署到传统虚拟专用服务器(VPS)的方法,例如由 Linode 、 DigitalOcean 或 Vultr 提供的那些。
SSH 密钥
我们将要介绍的所有工具都将通过互联网发送您的数据,以便部署您的软件。既然如此,拥有一个安全的连接是非常重要的。这篇文章中的许多例子将使用 SSH 密钥来加密连接。我建议专门为 CircleCI 创建一个全新的 SSH keypair。我最喜欢的创建 SSH 密钥的资源是 GitHub 的。
私钥应该通过 web 应用程序存储在 CircleCI 上。我们有指示你可以跟着到这里。对于您想要部署到的远程服务器上的用户,公钥应该存储在authorized_keys
文件中。例如,如果您正在部署一个 Linux 服务器prod@example.com
,那么公钥应该被附加到远程机器上的文件/home/prod/.ssh/authorized_keys
中。
Rsync
rsync
是一个已经存在了一段时间的文件传输工具。该名称来自“远程同步”,这意味着它允许您将文件从一个目录或机器传输到另一个目录或机器,但同时保持它们同步。这很有用,因为这个目的意味着rsync
可以比较远程服务器上的文件,如果它们已经存在,就不要传输它们,这有助于更快和更有效的部署。
当你有几个文件要传输时,比如用 Hugo 或 Jekyll 构建一个静态生成的网站时,这种方法非常有效。基本的 Rails、Flask 和 React 应用程序也可以这样部署。
使用
rsync -va --delete ./my-files/ user@example.com:/var/www/html
对于rsync
,您提供选项,您想要传输的文件或目录,然后您想要传输到哪里。
-
“v”表示打开详细度,以便我们可以在出现问题时看到发生了什么,而“a”表示存档模式。存档模式打开了许多有用的选项,如递归、复制文件权限和所有权等等。
-
--delete
-这告诉rsync
如果一个文件在 CircleCI 上被删除,它也应该从远程服务器上被删除。闲置的旧文件可能会导致不必要的问题,比如生产与您的本地环境不匹配,从而导致不必要的影响。 -
./my-files/
-我们要复制其内容的目录。请注意,有一个尾随斜线,尽管对于rsync
,没有尾随斜线。./my-files
没有尾随斜线意味着“复制整个目录,包括其中的所有内容。”./my-files/
末尾的斜杠表示“只复制目录的内容,而不复制目录本身。” -
user@example.com
--“用户”是我们要部署到的远程服务器“example.com”上的用户名。 -
:/var/www/html
-这是远程服务器上的文件路径,rsync
应该将文件发送到该路径。对于 web 服务器,这应该是 DocumentRoot。
安装
虽然一些 Docker 镜像可能已经安装了rsync
,但是官方 CircleCI 镜像和第三方 CI 构建镜像没有。然而,安装它相当简单:
# Ubuntu & Debian based Docker images
sudo apt-get update && sudo apt-get install rsync
# Alpine based Docker images
apk update && apk add rsync
CircleCI 示例
这是我的个人网站(Feliciano)的 CircleCI 配置片段。Tech),通过rsync
部署:
deploy:
docker:
- image: cibuilds/hugo:0.42.1
steps:
- attach_workspace:
at: src
- add_ssh_keys
- run: |
echo 'web01.revidian.net ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJiGRY6N9WYQ0vy6cTiwAgNbc6ueJmVo/EafBtmT7bcD6cQMbipYM/KfYQ2lCn2TxqWepZKYoyoVQXgArycCOns=' >> ~/.ssh/known_hosts
rsync -va --delete src/public/ staticweb@web01.revidian.net:www/feliciano.tech/public_html
相关工具
除了rsync
之外,还有其他类似的选项。被称为“安全复制”的“T1”和被称为“安全 FTP”的“T2”是两种工具,它们都利用 SSH 进行加密,并处理基本的文件传输过程,您可以使用它们部署到 VPS。
记下最后一条。
老式的 FTP 是完全不安全的,不应该使用。每当你想到 FTP,就想到 SFTP。
停靠点(SSH)
如果你在 Linode 或类似的提供商上运行 Dockerized 应用,你可能没有复杂的编排工具,如 Kubernetes 或 Docker Swarm running。当然这并不意味着你不能,但是这对于 VPS 用户来说不太常见。那么我们如何在不手动登录服务器的情况下,从 CircleCI“部署”一个 Docker 应用呢?让我们看一个例子:
deploy:
docker:
- image: circleci/golang:1.10
steps:
- attach_workspace:
at: src
- add_ssh_keys
- run: |
docker build .
docker login -u $DOCKER_USER -p $DOCKER_PASS
docker push myuser/myapp
echo 'example.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJiGRY6N9WYQ0vy6cTiwAgNbc6ueJmVo/EafBtmT7bcD6cQMbipYM/KfYQ2lCn2TxqWepZKYoyoVQXgArycCOns=' >> ~/.ssh/known_hosts
ssh root@example.com <<'ENDSSH'
docker pull myuser/myapp
docker stop my-app
docker rm my-app
docker run --name=my-app --restart=always -v $PWD:/app -d myuser/myapp
ENDSSH
在这个部署作业中,我们为示例应用程序构建了一个新的 Docker 映像,并将其推送到 Docker Hub。这使得该应用程序可以在 CircleCI 之外使用。然后,我们使用 SSH 命令的一个特性,该特性允许我们在远程机器上运行命令,在本例中是我们的生产机器。我们使用 SSH 登录,将新的 Docker 映像拖到生产机器上,停止、删除并使用更新后的映像重新启动应用程序。
为了简化 CircleCI 配置,我们还可以将远程 Docker 命令保存到名为update-app.sh
或类似的 Bash 脚本中,然后从 CircleCI 运行该脚本。看起来会像这样:
ssh root@example.com '/var/app/update-app.sh`
如果你尝试一下,让我知道你做得怎么样!
总而言之,如果您不需要像 Kubernetes 和 AWS S3 这样的大型提供商的灵活编排,使用 VPS 来部署您的应用程序是一个经常被忽略但可行的选择。我写这篇文章的目的是展示一些可以和 CircleCI 一起用于发布应用程序的其他部署选项。
Docker 部署——使用 Docker 和 Terraform | CircleCI 部署到 Google Cloud
我经常在会议和技术会议上发言,最近我回答了很多关于不断向云平台交付应用程序的问题,例如使用 HashiCorp Terraform 的谷歌云。在这篇文章中,我将演示如何使用 CI/CD pipelines、Docker 和 Terraform 将应用程序部署到 Google Cloud 实例中。在这个例子中,您将使用一个 Google 容器优化的 OS 主机映像创建一个新的 Google Cloud 实例。谷歌的容器优化操作系统是为运行 Docker 容器而优化的计算引擎虚拟机的操作系统映像。借助容器优化操作系统,您可以快速、高效、安全地将 Docker 容器放在 Google 云平台上。
本教程还演示了如何使用 Terraform 创建一个新的 Google Cloud 实例,并使用这个 CI/CD 教程 Docker 映像部署应用程序。该图像将从 Docker Hub 中提取,并在从 Terraform 创建的实例上运行。
先决条件
开始之前,您需要具备以下条件:
您还需要:
具备所有先决条件后,就可以继续下一部分了。
基础设施作为代码
基础设施即代码(IaC)是通过机器可读的定义文件来管理和配置云和 IT 资源的过程。IaC 使组织能够使用现代 DevOps 工具(如 Terraform )调配、管理和销毁计算资源。
在本文中,您将使用 IaC 原则和 Terraform 将您的应用程序部署到 Google Cloud。
创建一个谷歌云平台项目
使用这些指令创建一个新的谷歌云项目。
创建并获取谷歌云项目证书
您需要创建谷歌云凭证,以便使用 Terraform 执行管理操作。进入创建服务账户密钥页面。选择默认的服务账号或者新建一个,选择 JSON 作为 key 类型,点击创建。将这个 JSON 文件保存在terraform/google_cloud/
的根目录下。
重要安全提示:将文件重命名为cicd_demo_gcp_creds.json
,以保护您的 Google Cloud 凭据不会在公共 GitHub 存储库中被发布和暴露。您还可以通过简单地在这个项目的.gitignore
文件中添加凭证的 JSON 文件名来保护凭证的 JSON 文件不被释放。您必须非常谨慎地对待这个 JSON 文件中的数据,因为一旦暴露,任何拥有这些信息的人都可以侵入您的 Google Cloud 帐户,创建资源,并收取费用。
在本地安装 Terraform
设置地形
在终端中,运行:
cd terraform/google_cloud/
terraform init # this installs the Google Terraform plugins
接下来,您必须更改main.tf
文件中的一些值。您将更改 Terraform 变量的值以匹配您的信息。将变量project_name
的default
标签更改为您之前创建的项目名称:
variable "project_name" {
type = "string"
default = "cicd-workshops"
}
将变量docker_declaration
的default
标记的image
值:image: 'ariv3ra/python-cicd-workshop'
更改为您在 CI/CD 教程中构建并推送到 Docker Hub 的 Docker 映像:
variable "docker_declaration" {
type = "string"
# Change the image: string to match the Docker image you want to use
default = "spec:\n containers:\n - name: test-docker\n image: 'ariv3ra/python-cicd-workshop'\n stdin: false\n tty: false\n restartPolicy: Always\n"
}
地形图
terraform plan
命令用于创建执行计划。除非明确禁用,否则 Terraform 会执行刷新,然后确定需要执行哪些操作才能达到配置文件中指定的所需状态。这个命令是检查一组更改的执行计划是否符合您的期望的一种方便的方法,而不需要对实际资源或状态进行任何更改。
在终端中,运行:
terraform plan -out=plan.txt
这将向您显示一个漂亮的图表,其中列出了 Terraform 将创建或更改的项目。
地形应用
terraform apply
命令用于应用所需的更改,以达到所需的配置状态,或由 Terraform 执行计划生成的预定动作集。
在终端中,运行:
terraform apply plan.txt
这将执行 Terraform 计划,并尝试根据该计划和定义的 Docker 映像构建一个新的 Google Compute 实例。
Google 计算实例 IP 地址
当 Terraform 完成构建 Google 资产时,您应该会看到实例的公共 IP 地址,它应该类似于下面的输出:
Public IP Address = 104.196.11.156
复制列出的 IP 地址或 DNS,并将其粘贴到 web 浏览器中,在末尾附加端口 5000。完整的地址应该如下所示:
https://35.237.090.42:5000
新应用程序应该呈现欢迎消息和图像。该应用程序是一个 Docker 容器,由您构建并推送到 CircleCI 的 CI/CD intro tutorial Docker 映像派生而来。
地形破坏
现在你已经证明你的 Google Compute 实例和 Docker 容器可以工作了,你应该运行 terraform destroy
命令来销毁你在本教程中创建的资产。你可以让它继续运行,但要知道,在谷歌云平台上运行任何资产都是有成本的,你可能要为这些成本负责。谷歌为其免费试用注册提供了慷慨的 300 美元信用,但如果你让资产运行,你可以很容易地吃掉它。这取决于你,但是运行terraform destroy
将关闭任何运行资产。
摘要
在本文中,您使用 Terraform 从 Docker Hub 将示例应用程序部署到一个活动的 Google Cloud 实例。这个例子演示了在应用程序的 CI/CD 管道在 CircleCI 上构建为绿色后,如何使用 Terraform 手动部署应用程序。通过对项目的 CircleCI config.yml
文件进行一些额外的调整,您可以配置 CI/CD 管道,以便在管道中使用 Terraform 进行自动部署。配置自动地形部署有点复杂,需要更多的工程知识,但这绝对是可能的。这可能是未来博客帖子的主题,敬请关注!
如果你想了解更多关于 CircleCI 的信息,请查看文档网站。如果你遇到困难,你可以通过社区论坛联系 CircleCI 社区。如果你想了解使用 Terraform 部署基础设施的审批工作,请访问这篇博文。
使用 CircleCI API 构建部署摘要仪表板| CircleCI
CircleCI API 为开发人员提供了一个网关来检索关于他们的管道、项目和工作流的详细信息,包括哪些用户正在触发管道。这使得开发人员可以通过提供端点来更好地控制他们的 CI/CD 流程,可以从用户的应用程序或自动化系统远程调用这些端点来获取信息和触发流程。在本教程中,您将学习并练习如何使用 API 创建一个简单的个性化仪表板来监控您的部署管道。
先决条件
安装并设置好所有这些之后,是时候开始本教程了。
获取 CircleCI API 令牌
您的帐户需要完全的读写权限才能对 API 进行经过身份验证的调用。要授予这些权限,您需要创建一个个人 API 令牌。进入你的 CircleCI 用户设置,然后点击 个人 API 令牌 。点击创建新令牌按钮。在令牌名称字段中,输入您可能记得的名称,然后单击添加 API 令牌按钮。
将显示令牌,供您复制到安全位置。请确保现在复制它,因为它不会再次显示。
设置 Insights 仪表板项目
我们在本教程中创建的仪表板将是一个 Node.js 应用程序,它有几个端点用于调用 CircleCI API。应用程序将在其基础(/
)路径返回仪表板页面。
首先,创建一个新项目并导航到文件夹的根目录:
mkdir insights-dashboard
cd insights-dashboard
接下来,脚手架一个基本的package.json
文件:
npm init -y
需要安装五个软件包:
express
创建应用服务器axios
向 CircleCI API 发出HTTP
请求cors
处理 CORS 的问题dotenv
在环境变量中存储 API 令牌body-parser
解析 JSON 格式的请求数据
使用以下命令一次性安装所有这些组件:
npm install express axios cors dotenv body-parser
接下来,创建一个.env
文件来存储 API 令牌:
API_KEY=YOUR_API_TOKEN
用之前复制的个人 API 令牌替换YOUR_API_TOKEN
。
创建仪表板端点
正如我前面提到的,应用程序的根将返回仪表板页面,这是一个使用基本(/
)端点的index.html
文件。项目应用程序还使用其他端点。在项目的根目录下,创建一个新文件server.js
,输入以下代码:
require("dotenv").config();
const express = require("express");
const path = require("path");
const app = express();
const cors = require('cors');
let bodyParser = require("body-parser");
const axios = require("axios");
app.use(cors());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
let port = process.env.PORT || "5000";
const api_v1 = "https://circleci.com/api/v1.1/";
const api_v2 = "https://circleci.com/api/v2/";
axios.defaults.headers.common['Circle-Token'] = process.env.API_KEY;
app.get("/", (req, res) => {
res.sendFile(path.join(__dirname+'/index.html'));
});
app.get("/getprojects", async (req, res) => {
let projects = await axios.get(`${api_v1}projects`);
res.send(projects.data);
});
app.get("/getpipelines", async (req, res) => {
const project_slug = req.query.project_slug;
let pipelines = await axios.get(`${api_v2}project/${project_slug}/pipeline`);
res.send(pipelines.data);
})
app.post("/triggerpipeline", async (req, res) => {
const project_slug = req.body.project_slug;
try {
const trigger = await axios.post(`${api_v2}project/${project_slug}/pipeline`);
res.send(trigger.data);
} catch (error) {
res.send(error)
}
})
app.get("/getworkflows/:pipeline_id", async (req, res) => {
const pipeline_id = req.params.pipeline_id;
let workflows = await axios.get(`${api_v2}pipeline/${pipeline_id}/workflow`);
res.send(workflows.data);
})
app.listen(port, () => {
console.log(`App Running at http://localhost:${port}`);
})
让我花点时间来分析一下这个文件中发生了什么。首先,导入所需的包,并为cors
和body-parser
设置中间件。接下来,api_v1
和api_v2
被定义为分别保存 CircleCI API 版本 1 和版本 2 的 URL。
然后,axios
模块被配置为通过将Circle-Token
报头设置为存储在环境文件(.env
)中的令牌来发送每个请求中的 API 令牌。
接下来设置基本(/
)端点以返回包含仪表板代码的index.html
。该文件将在下一节中创建。
其他端点定义如下:
-
使用 CircleCI API 版本 1 从您的帐户中检索项目列表。API 版本 2 不支持检索项目,但它已经在工作中了。
-
/getpipelines
用一个project_slug
调用 v2 API 来检索一个项目上已经触发的管道。project_slug
是 CircleCI 项目的“三元组”标识符格式。它的形式是<project_type>/<org_name>/<repo_name>
。你可以阅读这篇文章了解更多信息。 -
/triggerpipeline
用一个project_slug
调用 v2 API 来触发一个新的管道在一个项目上运行。
最后,应用程序被编程为监听指定的端口。
要完成本节教程,请打开package.json
并添加一个start
脚本:
"scripts" : {
.....,
"start": "node server.js"
}
创建仪表板页面
是时候创建仪表板了。该应用程序将有两列,一列用于项目,这将立即加载。另一列将加载管道。还会有一个触发管道按钮来运行一个选定项目的新管道。
为了构建仪表板 UI 和功能,我们将使用 Bootstrap 进行样式设计,使用 Vue.js 作为前端框架。我们还将在前端使用 axios 对我们应用程序的端点进行 API 调用。如果你不理解 Vue.js,没有必要担心。你可以使用你喜欢的任何其他框架,甚至是普通的 Javascript 来实现相同的功能。
在项目的根目录下,创建index.html
文件并输入:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.21.0/axios.min.js" integrity="sha512-DZqqY3PiOvTP9HkjIWgjO6ouCbq+dxqWoJZ/Q+zPYNHmlnI2dQnbJ5bxAHpAMw+LXRm4D72EIRXzvcHQtE8/VQ==" crossorigin="anonymous"></script>
<title>Insights Dashboard</title>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<a class="navbar-brand" href="/#">My CircleCI Pipelines Dashboard</a>
<button
class="navbar-toggler"
type="button"
data-toggle="collapse"
data-target="#navbarText"
aria-controls="navbarText"
aria-expanded="false"
aria-label="Toggle navigation">
<span class="navbar-toggler-icon" />
</button>
</nav>
<div id="app">
<div class="container">
<div class="row">
<div class="col-md-6" id="projects-section">
<p v-if="loadingProjects">
<i>Loading Projects...</i>
</p>
<ul v-else id="list" class="list-group">
<li class="list-group-item" v-for="project in projects" v-bind:class="{ active: selectedProject.reponame == project.reponame }" @click="loadPipelines(project)">
{{project.reponame}}
</li>
</ul>
</div>
<div class="col-md-6">
<div v-if="selectedProject.reponame">
<h2>Pipelines <span class="text-primary">[{{selectedProject.reponame}}]</span></h2>
<p>
<button @click="triggerPipeline()" type="button" class="btn btn-success" :disabled="triggeringProjectPipeline">
{{triggeringProjectPipeline ? "Procesing" : "Trigger Pipeline"}}
</button>
</p>
<p v-if="loadingPipelines">
<i>Loading Pipelines</i>
</p>
<div v-else class="list-group" id="pipelines-section">
<a v-for="pipeline in pipelines" href="#" class="list-group-item list-group-item-action">
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1">
{{pipeline.number}} -
<span v-if="pipeline.state == 'errored'" class="text-danger">Failed</span>
<span v-else class="text-success">Passed</span>
</h5>
<small>{{pipeline.created_at.substring(0, 10)}}</small>
</div>
<p class="mb-1" v-if="pipeline.trigger">
Trigger Type: <span class="text-danger">{{pipeline.trigger.type}}</span> <br />
Recieved At: <span class="text-sucess">{{pipeline.trigger.received_at.substring(0, 10)}}</span> <br />
Triggered By: <span class="text-primary">{{pipeline.trigger.actor.login}}</span></p>
<small>ID: {{pipeline.id}}</small>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
loadingProjects : false,
projects: [],
selectedProject : {},
loadingPipelines : false,
pipelines : [],
triggeringProjectPipeline : false
},
async created(){
this.loadingProjects = true;
let projects = await axios.get(`getprojects`);
this.projects = projects.data;
this.loadingProjects = false;
},
methods : {
loadPipelines : async function (project) {
this.selectedProject = project;
this.loadingPipelines = true;
const project_slug = `${project.vcs_type}/${project.username}/${project.reponame}`;
let pipelines = await axios.get(`getpipelines?project_slug=${project_slug}`);
console.log(pipelines);
this.pipelines = pipelines.data.items;
this.loadingPipelines = false;
},
triggerPipeline : async function () {
this.triggeringProjectPipeline = true;
let project = this.selectedProject;
const project_slug = `${project.vcs_type}/${project.username}/${project.reponame}`;
let trigger = await axios.post(`triggerpipeline`, {
project_slug
});
console.log(trigger);
this.loadPipelines(project);
this.triggeringProjectPipeline = false;
}
}
})
</script>
<style>
#app {
margin-top: 50px;
}
#projects-section, #pipelines-section{
height: 600px;
overflow: scroll;
}
</style>
</body>
</html>
在前面的代码中,引导 CSS、Vue.js 和axios
的库是从它们各自的 cdn 中加载的。在页面的主体中,用 Bootstrap 的网格系统创建了两列来格式化项目部分,另一列用于管道和触发管道按钮。
在 script 标记中,创建了一个新的 Vue.js 应用程序实例,用数据变量来保存projects
、pipelines
和selectedProject
。当分别向/getprojects
、/getpipelines
和/triggerpipeline
端点发出 API 请求时,还会创建用于loadingProjects
、loadingPipelines
和triggeringProjectPipeline
的变量来管理应用程序状态。
一旦仪表板加载,Vue.js created
生命周期挂钩用于从您的帐户加载项目。还定义了加载管道和触发新管道在 Vue.js 实例的methods
属性中运行的方法。
最后,在<style>
部分,基本样式被添加到页面中。
测试仪表板项目
是时候了!在项目的根目录下,运行:
npm start
应用程序应该在http://localhost:5000
启动。在浏览器中加载这个地址,在简短的加载消息之后,您应该会看到您的项目。
单击项目以加载其管线。
单击某个项目时,该项目的管道将在下一列中加载。每个管道条目都包含详细信息,如管道状态(通过或失败)、触发管道的用户/进程、管道触发日期。还有更多。
也可以点击触发管道按钮运行新的管道。管道列表将被刷新以显示最近触发的管道。
结论
正如我们在本教程中所演示的,CircleCI API 使 DevOps 专业人员能够获得有用的信息,并为我们的项目和管道创建个性化的体验。只需几行代码,我们就能够为我们的项目开发一个交互式仪表板。想象一下您可以用 CircleCI API 中的其余可用端点做些什么。
当谈到开发团队的成功时,找到正确的 DevOps 指标来衡量是至关重要的。了解如何在 2020 年软件交付状态中用四个关键基准来衡量 DevOps 的成功:工程团队的数据支持基准。
编码快乐!
Fikayo Adepoju 是 LinkedIn Learning(Lynda.com)的作者、全栈开发人员、技术作者和技术内容创建者,精通 Web 和移动技术以及 DevOps,拥有 10 多年开发可扩展分布式应用程序的经验。他为 CircleCI、Twilio、Auth0 和 New Stack 博客撰写了 40 多篇文章,并且在他的个人媒体页面上,他喜欢与尽可能多的从中受益的开发人员分享他的知识。你也可以在 Udemy 上查看他的视频课程。
设计一个包管理器:CircleCI orbs 的内幕
原文:https://circleci.com/blog/designing-a-package-manager-from-the-ground-up/
不到三个月前,我们发布了 CircleCI orbs ,这是我们针对 CircleCI 配置的软件包管理生态系统。在那段时间里,我们已经看到在最初的 10 周内创建了超过 300 个 orb,超过 200 个组织在超过 1,000 个项目的数万个构建中使用 orb。我们还通过新的技术合作伙伴计划推出了 20 多个官方合作伙伴 orb。我们非常感谢巨大而积极的回应。
在这篇文章中,我想回顾并分享创建和推出 CircleCI orbs 的关键设计决策。如果您现在正在使用 orbs,并且想要了解如何从它们那里获得最大的收益,或者如果您正在考虑设计自己的包管理系统,那么这篇文章就是为您准备的。
什么是 CircleCI 球体?
orb 是 CircleCI 配置的可共享包。像大多数其他代码打包系统一样,orb 提供了一组通用的抽象结构元素,使得在您的组织以及更广泛的用户生态系统中重用经过测试、封装的构建组件变得切实可行。orb 有一个用 YAML 语法定义的领域特定语言(DSL ),它表达了我们的构建配置的语义。这使得在构建配置中为封装的命令、作业和执行器编写惯用接口变得简单。
orb 还提供包管理基础设施。这使得发布清晰版本化的 orb,然后导入它们用于项目变得简单。
球体的设计是为了解决什么问题?
我们的工作是帮助团队激活并加速他们的软件交付。充分利用 CircleCI 的关键要素之一是我们的构建配置,这是一种基于 YAML 的语义,用于描述 CI 管道的工作流、作业和环境。当我们开始构建 orb 时,我们希望解决与构建配置相关的三个关键问题:
1。更好的干支持
circle ci 2.0 中的配置被设计成高度透明、富有表现力和确定性的。然而,这些特征也会使我们的基本语义变得冗长和重复。如果没有好的快捷方式和甜言蜜语,配置可能会有很多样板代码,阻碍项目的设置,并且随着复杂程度和范围的增加,配置变得难以使用。
2。跨项目的代码重用
许多客户想要更好的方法来跨项目共享配置。CircleCI 配置以前不容易在团队之间共享,这造成了不必要的冗余并降低了团队的速度。我们拥有大型团队的客户希望能够轻松地传播和实施通用的模式和策略,并通过共享的实践来帮助他们的团队改进。
3。更容易实现通用配置
开发人员试图避免重新发明东西或重新解决已解决的问题。在引导代码时,只要实用可靠,他们就希望使用现成的、经过改进的封装。在 CircleCI 中,对于第一次使用的用户来说,从空白页开始可能会令人望而生畏,我们希望让从一无所有到有用的东西变得更容易。
关键设计决策(以及我们做出这些决策的原因)
正如我们所料,设计一个新的包管理系统并不是一个简单的过程。在构建 orbs 时,我们需要平衡可接近性、可表达性、可移植性和确定性。我们回顾了其他包管理系统以及各种配置模板方法,并很快集中在我们想要合并的几个关键元素上。
因为 orb 比大多数通用包管理器更专注于它们的范围,所以我们在设计决策中有更多的主见。在这个过程中,我们对设计的各个部分进行了内部和外部预览,这使得我们可以在代码中嵌入任何东西之前获得快速的反馈。
在进入 orb 本身的设计之前,让我们从我们正在构建的底层 CircleCI 配置模型的一些上下文开始。
关于 CircleCI 配置的现有决策
当我们开始 CircleCI orbs 的设计过程时,我们知道我们将坚持 CircleCI 配置的现有设计原则:
1。代码中的配置:总是允许代码本身包含需要完成的配置,除非设置或其他输入绝对有必要存在于代码之外(例如:项目设置打算自动应用于所有分支,或者秘密注入和安全,打算存在于代码库之外)。
2。确定性:给定相同的输入,每个构建都应该有相同的行为方式。这可以防止你无法控制的事情改变你,同时减轻 CircleCI 不得不做出并执行关于你想要如何运行你的构建的假设。
3。使用 YAML 是因为它提供了一种在语法权重和表达性之间取得合理平衡的方式来创作数据结构。让配置成为数据而不是编程语言,可以提供简单可靠的工具来进行配置语法和模式验证、在构建过程中进行各种静态分析和数据转换,以及使用一流元数据进行自动化文档编制。例如,Jenkins 插件的配置本身不是可执行代码。另一方面,orb 可以被推理为配置组合,而不是特定环境中的可执行软件。虽然这并没有解决所有的依赖性和安全性问题,但是它在您希望如何配置执行期间运行时环境内部发生的构建之间创建了更清晰的界限。
4。构建行为的声明性:circle ci 配置的语义围绕着我们平台内部构建执行的核心域模型。核心结构由调用和协调作业的工作流驱动,这些作业表达了一组要运行的步骤以及运行这些步骤的执行环境。我们的配置代码本质上是您构建过程的元代码,因为我们提供了上层结构,您可以在其中表达自己的运行时命令和流程编排。我们想让你专注于你的代码在运行时内要做什么,尽可能不碍事。使用声明性语法可以给你一组有表现力的原语,而不需要你学习太多关于我们内部系统如何工作的知识,或者学习一些新的编程语言。
在着手构建 orb 时,CircleCI 配置的现有设计成了我们的关键约束。除了这些限制,orb 设计还有三个关键领域(排名不分先后):
*** orb 注册表的设计
-
orbs 的开发生命周期
-
我们的领域特定语言(DSL)的语义
下面,我将逐一介绍这些领域以及我们所做的决定。
设计 Orb 注册表
我们最初的设计建议从位于您的.circleci
文件夹中的“本地”球体开始,这些球体将在运行时被拉入。里面有球体。circleci 被认为是不可接受的风险,因为我们与 GitHub 的互动方式。“不要把 git 当成一个包管理器”是我们内部对这种情况的明确警告。这产生了拥有我们自己的注册中心的需要,这无疑增加了大量的范围(大约 60-90 天的时间)并创建了一个清晰的设计边界。
1。所有的球体都存在于一个命名空间中:所有的球体都存在于一个命名空间中。没有“空”的名称空间,也没有为 CircleCI 或“官方”orb 保留的特殊默认值,如_
。我们决定不希望我们创作的 orb 被认为是默认集合,或者在我们的命名空间方案中有特殊的意义。我们可能会在未来引入一个认证的 Orbs 程序或类似程序,但这将在 orb 上提供一流的元数据,明确定义包含,而不是依赖于来自特殊名称空间的含义。
2。语义版本化和锁定: CircleCI 希望允许 orb 作者动态地向 orb 添加特性和修复。同时,我们希望防止 orb 用户下的事情发生变化:修复用户使用的 orb,以便用户的配置保持静态,除非用户另有指定。CircleCI 选择在所有发布的修订版上强制执行严格的语义版本化格式。当导入时,我们允许 orb 用户锁定一个特定的版本或承担损坏的风险,并使用最新的版本(易变的)。
3。“易变的”而不是“最新的”:我们选择使用“易变的”而不是“最新的”,因为我们希望鼓励使用特定的版本来获得更大的确定性。我们希望使用volatile
的人明白他们正在做的事情会有被破坏的风险。我们认为“最新的”听起来新鲜而新颖,而“易变的”更好地表达了当您愿意采取可能会毫无预警地任意变异的上游依赖时所发生的事情。同样值得注意的是,我们没有默认“volatile”或任何版本——在调用 orbs 时,您必须至少指定一个部分 semver 或“volatile”。
4。认证与第三方 orb:认证意味着 CircleCI 将其视为我们平台的一部分。如果使用 2.1 或更高版本的配置,任何人都可以使用它们,而无需额外选择加入。目前,只有circleci
名称空间得到了认证,因为这些 orb 是我们自己编写的。所有其他人都被视为第三方。
5。开放与私有球体:所有的球体都是开放的,这意味着它们是全球可读的。任何人都可以使用它们并看到它们的来源。我们不想在你的代码和秘密的运行时环境中引入黑盒,所以如果你要在你的工作中运行 orb,你应该能够看到它们在做什么,这很重要。我们很可能会在未来增加一些拥有私人球体的方法。
Orb 发展决策
orbs 系统的核心是开发 orbs 的开发人员如何工作。这里的首要任务是平衡迭代的容易程度和从小处着手,并考虑到持久性和不变性,允许 orb 的用户能够将它们合并到他们的构建中。以下是 orb 创作体验的主要特征。
1。修订版是不可变的:为了防止神秘的变化出现在那些使用 orb 的人的构建中,我们不允许在 orb 修订版上线后对其进行修改。要发布新版本的代码,您需要发布新的修订版。
2。开发与生产 orb:一旦我们决定对生产 orb 实施严格的、不可变的版本控制,我们希望有一种好的方式让你开发 orb 而不污染你的 semver 进程。因此,orb 既可以作为“dev:foo”发布,也可以作为语义版本化的生产 orb 发布。开发 orb 可以被团队中的任何人更改,并在最后一次发布日期后 90 天到期。生产 orb 是不可变的和持久的,因此您的构建配置不会受到您使用的 orb 中的意外变化的影响。
3。注册时依赖关系解析:如果一个 orb (my-orb)导入了其他 orb,我们将在 my-orb 被添加到注册表时解析并锁定那些依赖关系。例如,假设您发布了 my-orb 的 1.2.0 版本,它包含这个 orb 调用:foo-orb: somenamespace/some-orb:volatile
–当您注册 my-orb 的 1.2.0 版本时,foo-orb 的最新版本将被整合到 my-orb 的 1.2.0 版本中。如果 foo-orb 的一个新版本发布了,它不会被合并到 my-orb 中,直到你发布一个新版本。我们建议选择您导入的 orb 的完全限定版本,以确保确定性行为。
4。透明性:如果你可以执行一个 orb,你可以看到这个 orb 的源代码。这就是为什么你永远不会在你的工作中执行一个黑盒,那里有你的代码和秘密。orb 不太像你的核心软件,而更像一个你可以复制和粘贴的配置。orb 是你构建过程的一部分,所以如果你能执行它们,你应该能看到它们做了什么。
DSL 设计决策
在 orbs 内部,我们基于 YAML 的领域特定语言(DSL)的语法和语义需要得到增强,以允许参数化和重用。以下是我们在这方面做出的一些重要决定。
1。orb 打包特定的配置元素,而不是提供通用的模板解决方案。环顾其他工具,我们看到一些使用通用模板在项目间共享代码片段的配置实例。我们很早就决定将 orb 的重点放在使用我们的配置 DSL 的语义上,并允许调用特定的元素,这样就可以在特定的范围内使用参数,并避免意外的冲突。这种方法也使得配置更容易阅读和推理。
2。内置/一流元数据。CircleCI 允许描述键作为 orbs 结构的一部分,因此生成文档或通读代码更容易,不需要额外的结构注释。
3。orb 是 config.yml. 的子集。您可能会注意到您的config.yml
文件中的配置格式与 orb 非常相似。一开始,很明显 config.yml 实际上是一种特殊的 orb——您可以将它视为在 CircleCI 上运行您的构建的“根 orb”。
下一步是什么?
我们很高兴看到这么多团队在短短几周内发布和使用 orbs。在整个 2019 年,我们希望为 orb 添加一些新功能,并继续构建我们自己的 orb,并与我们的合作伙伴合作,使与他们的系统集成更加容易。下面是几个资源,可以了解更多信息或参与帮助我们塑造构建配置的未来。
要了解更多关于使用或创作 orb 的信息,请参阅文档:https://circleci.com/docs/orb-intro/
要查看哪些 Orb 可以在您的配置中使用,请查看 Orb 注册表:https://circleci.com/developer/orbs
要提出功能请求或投票支持现有请求,请查看我们的创意板:https://ideas.circleci.com/?category=6605281645345952372
关于球体的一般讨论见我们的讨论板:https://discuss.circleci.com/c/orbs
相关博文:**
使用 gitguardian | circleci 检测 hhardcore 机密
原文:https://circleci.com/blog/detect-hardcoded-secrets-with-gitguardian/
开发人员正以前所未有的速度使用他们需要的软件生态系统来构建功能。这些不断扩展的选项包括开源库和包、SaaS 工具、部署系统、云服务等等。为了保证安全,我们总是需要一样东西:秘密。
什么是秘密?
机密是应用程序、服务或基础结构中使用的数字身份验证凭据(API 密钥、证书和令牌)。就像密码(在 MFA 的情况下加上一个设备)用于认证一个人一样,密码用于认证一个系统以实现互操作性。
观看视频:什么是秘密?
为什么在 CI/CD 环境中秘密是一个问题?
当软件工程师使用 CI/CD 管道将工件、应用和基础设施部署到多个环境中时,他们需要处理越来越多的凭证。有很多地方秘密会不安全地暴露出来:
- 源代码
- 构建、测试或部署 CI/CD 工作流
- 容器图像层
- 转轮控制台输出
凭据泄露不仅仅是一个安全问题;旋转泄漏的机密会中断 CI/CD 工作流。
秘密是如何出现在源代码中的?
两个字:人为失误。
绝大多数泄露的凭证都是错误的,并不是出于恶意。硬编码凭证可能是一种临时的解决方案,有时开发人员并没有意识到 Git 实际上在跟踪一个被删除的秘密。新开发人员不知道正确的程序,或者测试被跳过。可能出现的错误数不胜数。
为什么硬编码的秘密不同于其他类型的漏洞?
不像其他漏洞,它指出了代码中的特定弱点,检测秘密需要一个项目的整个代码库历史。
当一个开发人员错误地犯了一个秘密时,有两种可能性:要么承认,要么不承认。
在前一种情况下,一个非常常见的错误是删除它并简单地提交更改。这个秘密从源代码的当前状态中消失了,但是它仍然在提交历史中!
在后一种情况下,秘密很可能会到达远程版本控制系统(VCS)。在这一点上,秘密已经被认为是泄漏了(最好的情况是,它将在代码审查阶段被检测到,但是秘密可能已经需要在那一点上被旋转)。
发现隐藏在代码库历史深处的有效秘密并不罕见。秘密检测需要考虑这种攻击面和扫描存储库的增量变化,以防止这种泄漏。
GitGuardian 入门
在本教程中,您将学习如何将 GitGuardian 实时监控添加到 CircleCI 工作流中,以扫描每个新提交的秘密。
GitGuardian 在历史记录或增量提交中检测存储库中的秘密。秘密检测发生在开发生命周期的多个阶段:在带有预提交钩子或预推钩子的开发人员的本地机器上,在预接收钩子中或在 CI 环境中。
有了 GitGuardian dashboard,可以在公司范围内实现可见性,以同时保护所有存储库。
仪表板还使开发人员和 AppSec 工程师能够在整个补救过程中进行协作。我们不会在教程中讨论这个,但是你可以在文档中了解更多。
先决条件
要学习本教程,您需要:
- 一个圆的账户
- GitHub 的一个账户
- 一个 GitGuardian 账户
分叉样本存储库
在本教程中,您将使用来自 GitGuardian 的sample_secrets
测试库。这个存储库包含各种用于测试目的的秘密。将其转到您的 GitHub 用户帐户或您是管理员的 GitHub 组织。
然后,打开 CircleCI 项目页面,点击sample_secrets
名称,然后选择更快:提交一个启动 CI 管道到一个新的分支。
这在存储库中创建了新的分支circleci-project-setup
,包含了由./circleci/config.yml
文件配置的演示工作流say-hello-workflow
。
创建 GitGuardian API 令牌
你需要一个 GitGuardian API 令牌来使用 GitGuardian orb。从 GitGuardian 仪表盘,转到 API >个人访问令牌,然后点击创建令牌。给令牌一个scan
范围和一个容易记住的名称:
复制令牌并放在手边;这是你唯一可以观看的时间。
注意: 如果您正在使用 GitGuardian 的商业计划或 30 天商业试用,请创建一个服务帐户,而不是个人访问令牌。服务帐户是一种特殊类型的 API 键,用于表示非人类用户,如 CI runner。要创建一个,请转到 API >服务帐户并遵循相同的步骤。
从 CircleCI 仪表板中,单击sample_secrets
项目,然后单击项目设置>环境变量。点击添加环境变量。将其命名为GITGUARDIAN_API_KEY
,并赋予它与您之前复制的令牌相同的值。
使用 ggshield 扫描增量更改
您现在需要在 CircleCI config.yml
中添加一个工作流来使用ggshield
orb。
用以下内容复制并替换该文件:
version: 2.1
orbs:
ggshield: gitguardian/ggshield@volatile
workflows:
scan_my_commits:
jobs:
- ggshield/scan:
name: ggshield-scan
base_revision: <<pipeline.git.base_revision>>
revision: <<pipeline.git.revision>>
你也可以在ggshield
orb 注册页面找到这个片段。
当管道被触发时,base_revision
和revision
值将被填充:
base_revision
是要扫描的第一个提交的提交 ID。revision
是上次扫描的提交的 ID。
在这个配置中,只扫描最新的提交,这对于 CI 管道来说很方便。您可能不想在每次管道启动时扫描整个 git 历史。该扫描对自上次修订以来的所有提交进行操作,以确保没有秘密被提交然后被删除。
当您处理完config.yml
文件后,提交它,推送它,并转到 CircleCI 仪表板来观看管道启动。如果这是你第一次使用第三方宝珠,你可能不得不接受在组织设置>安全>宝珠安全设置中使用它们。
单击作业以了解有个提交要扫描:1 个。
#!/bin/bash -eo pipefail
ggshield secret scan -v ci
CIRCLE_RANGE: dea39f827dfe23f06f4ea63d7fb16ab0c363db9d...90220851160dcf018f372536da223dc0396aa247
CIRCLE_SHA1: 90220851160dcf018f372536da223dc0396aa247
Commits to scan: 1
Scanning Commits---------------------------------] 0%Scanning Commits [####################################] 100%
secrets-engine-version: 2.71.0
No secrets have been found
commit 90220851160dcf018f372536da223dc0396aa247
Author: ***
Date: ***
CircleCI received exit code 0
要验证屏蔽是否如预期的那样工作,只需对测试存储库的一个文件提交一个更改。例如,打开sample_secrets/bucket_s3.py
文件,添加或删除尾部空白,然后提交这个更改(确保在circle-project-setup
分支上)。
这将失败,因为 ggshield 将扫描最近的提交并检测文件中的两个秘密:
#!/bin/bash -eo pipefail
ggshield secret scan -v ci
CIRCLE_RANGE: 90220851160dcf018f372536da223dc0396aa247...2d08c13226628ecfb3ee9a07001c185915a84adf
CIRCLE_SHA1: 2d08c13226628ecfb3ee9a07001c185915a84adf
Commits to scan: 1
Scanning Commits---------------------------------] 0%Scanning Commits [####################################] 100%
secrets-engine-version: 2.71.0
commit 2d08c13226628ecfb3ee9a07001c185915a84adf
Author: XXXX
Date: XXXX
🛡️ ⚔️ 🛡️ 2 incidents have been found in file bucket_s3.py
>>> Incident 1(Secrets detection): AWS Keys (Validity: Invalid) (Ignore with SHA: 9f2785cab705507aaea637b8b38d8e1ff9ce8a4334dda586187cbb018ed33163) (1 occurrence)
8 8 |
9 9 | def aws_upload(data: Dict):
10 | database = aws_lib.connect("AKIA************WSZ5", "hjshnk5**************************89sjkja") |_____client_id____|
10 | database = aws_lib.connect("AKIA************WSZ5", "hjshnk5**************************89sjkja")
10 | database = aws_lib.connect("AKIA************WSZ5", "hjshnk5**************************89sjkjb")
11 11 | database.push(data)
>>> Incident 2(Secrets detection): AWS Keys (Validity: Invalid) (Ignore with SHA: e8077f59453457d2b3d980be4d8655eaa901c7aa8810a6079b429477e07a57f9) (1 occurrence)
9 9 | def aws_upload(data: Dict):
10 | database = aws_lib.connect("AKIA************WSZ5", "hjshnk5**************************89sjkja")
10 | database = aws_lib.connect("AKIA************WSZ5", "hjshnk5**************************89sjkjb")
|_____client_id____|
10 | database = aws_lib.connect("AKIA************WSZ5", "hjshnk5**************************89sjkjb")
|_____________client_secret____________|
11 11 | database.push(data)
Exited with code exit status 1
CircleCI received exit code 1
有效性:无效告诉你两件事:
- 秘密可以被检查(情况并非总是如此)。
- 这个秘密不再有效了。
更进一步:扫描提交历史
但是,如果您想扫描所有过去的提交来寻找秘密呢?当您分叉sample_secrets
存储库时,GitGuardian 已经为您完成了历史扫描(这是默认行为)。
进入你的 GitGuardian 仪表板,在周界页面搜索sample_secrets
信号源。您应该看到 GitGuardian 在存储库中检测到了 9 个公开的秘密事件。
如果需要,您可以再次扫描选择的源。
单击源以显示机密表。历史扫描期间检测到的事件会被标记。
您可以用命令ggshield scan repo
扫描任何任意的 git 历史,但是没有专用的 orb。
更进一步:补救和开发人员工作流程
如果你能走到这一步,恭喜你!可以肯定的是,提交给这个存储库的任何秘密都会打破管道,并在仪表板中报告,以及所有其他过去的事件。你可以阅读更多关于如何利用它们来分配事件、协作和组织清理你的存储库泄露的秘密。
这里是我们给所有 GitGuardian 用户的一个建议:预防总是比补救更好,所以要尽早在开发人员的工作流程中集成秘密检测。
为了理解为什么,想象一下 GitGuardian 在 CircleCI 工作流中检测到一个广泛使用的秘密。最佳做法是立即撤销并轮换它,就好像它被破坏了一样,即使它没有被破坏。但事实是,轮换一个秘密几乎总是一项艰难的工作。对许多人来说,这可能意味着工作流程的中断。它可能会在整个 CI/CD 链中,甚至在生产中导致意外的故障。
这就是为什么我们一直提倡在开发者工作流中集成 GitGuardian 和 ggshield,作为预提交、预推送(客户端),或者预接收(服务器端)钩子,确保没有秘密可以在第一时间到达版本控制系统。
您还可以将 GitGuardian 原生集成到源代码管理平台中:
结论
本教程演示了秘密是如何容易被泄露的。与运行时漏洞不同,泄漏的秘密可能会持续存在于旧的提交中,并构成真正的威胁。这就是为什么在您的 CI 工作流中使用 secrets detector 对于代码安全性是必不可少的。
这种意识是在安全、运营和开发人员之间建立共同责任文化的重要第一步,以防止生产问题,保持管道运行,并尽快补救问题。
想了解更多?访问 GitGuardian 文档和博客获取最佳实践、备忘单和更多内容。
开发恐怖故事,第二部分- CircleCI
来自出版商的说明:您已经找到了我们的一些旧内容,这些内容可能已经过时和/或不正确。尝试在我们的文档或博客中搜索最新信息。
去年万圣节,我们发出呼吁,寻找多年来一直困扰着你的开发者墓穴的故事。
我们玩得很开心,决定再来一次,时间安排得很诡异…
请继续阅读那些让你彻夜难眠的令人毛骨悚然的开发故事:
“在我上一份工作中,您的新密码不能包含(作为子串)您之前的 5 个密码中的任何一个。所以他们被要求存储所有明文,以确保这一点。”
“我的公司决定下一步从 om 切换到 React,所以现在我们的前端有三个框架”
“我们需要硬件进行测试。我们负担不起。把它运出去,看看会发生什么。我们可能永远也不会理解不开心的顾客。”
“时间戳仅在本地时间。祝夏令时和凌晨 2 点的活动顺利。”
“…如果已经有一个名为 something 的列,例如“生日”,而这个人(创建数据库的人)想要使用同名的列,而不是重用已经存在的列并用正确的数据填充它,他将创建一个名为“BirtthDate”的列"
我:“嗨,只是写信告诉你,当给定有效数据时,新的 API 将返回一个 500 错误和“ok”消息,并且当请求时,数据随后出现在列表中,好像它都工作正常……”他们:“是的,这是预期的,只需将 500 错误和“OK”消息映射,就好像它是一个 200“Me”:……..达福克”
”在前端做了修改的卡片说道。有些棱角分明,有些自举,有些余烬,当然还有 knockout # its not clutterits polyglot”
"创业:希望我成为 fullstack +dba +项目经理+测试+ GUI 设计师+ scrum master . "
“…必须在我的 jdbc 格式的连接字符串中对我的密码进行 urlencode,然后必须对其进行 base64 编码,并通过一些替换将其放在 yaml 文件中,以便它可以编译为 json,并且不会由于特殊字符而被错误地转义…”
“自制的 SQL Server 加密插件有时会破坏客户数据,而这些数据是生死攸关的。无法重新编译插件。发现导致使用回退密钥的竞争情况。教技术支持用后备密钥解密。浏览编译过的机器码。发现由特定的双字节操作码序列触发的竞争条件,该操作码序列碰巧是可读的 ASCII 码并且是唯一的。教导技术支持人员在 DLL 中使用 Notepad++搜索并替换该操作码序列,将逗号更改为波浪号,从而一劳永逸地解决问题。”
围着篝火讲述开发人员的恐怖故事
原文:https://circleci.com/blog/dev-horror-stories-to-tell-around-the-campfire/
作为一名开发人员,生活可能会有许多令人毛骨悚然的变化。
从长期困扰您的论坛难题,到您发现潜伏在遗留代码中的偷偷摸摸的 bug,作为开发人员,您遇到的事情可能会非常令人震惊。为了庆祝万圣节,请继续阅读我们 CircleCI 开发者的一些恐怖故事:
“我曾经为一家 VPS 提供商提供技术支持,我告诉一位客户,他们的磁盘映像被破坏了,因此他们应该删除它并从备份中恢复。备份也遭到破坏,我们无法尝试修复他们的映像,因为他们删除了它……”
“让一切以根运行。说够了。”
“我曾经在运行 Ansible playbook 时删除了我们车队中每台机器上的/home,因为 Jinja 模板的规则以及过滤和循环的操作顺序不清楚,所以没有删除/home/\(employee,\)employee 是一个空字符串。”
“我曾在一家初创公司工作,当时只有 4 个人,包括我自己,老板/自认为是本周名人的人在泡沫破裂前的 90 年代赚了钱,他擅长营销,但几乎没有技术知识。有一天,这款应用发布了一个 bug,那天晚些时候,当我告诉他 bug 的根本原因时,他的反应是‘为什么没有一个备份功能可以在出现 bug 的情况下工作?我那天提出了辞呈。"
“我曾经在一家网络保险公司工作,该公司举行了一次发布会/聚会,所有高管花了一个多小时谈论公司的表现,然后第二天就解雇了三分之一的员工。”
“我最近的一家公司有大约 3 年的建筑师旋转门,产品从纯 Clojure/ClojureScript 发展到 Python、Go、Clojure、ClojureScript、Java、JavaScript,以及一些 C++的加入。”
"让我们不要使用 Kubernetes,并尝试推出我们自己的无状态 Kubernetes . "
“一家老公司从主值文件和 jinja 模板呈现每个微服务配置文件,然后将配置部署到 zookeeper 并直接部署到运行各种服务的容器中。这至少达到了你预期的 1/4。”
“我曾经继承运行一个 webservice,它是 lighttp,使用 CGI 运行 bash 脚本,使用 sed/awk/cut 解析 env 变量,如查询字符串和路径,以提取参数,然后使用 touch 和 rm 加上一些在文件系统上精心维护的状态,而不是使用真正的 DB -他们甚至没有使用 SQLite!”
"将一个整体作为一个依赖,重构为微服务."
有你自己可怕的故事?将你的#devhorror 故事分享到@CircleCI
我从开发 GitLab 支持功能| CircleCI 中学到了什么
原文:https://circleci.com/blog/developing-support-for-gitlab-teams/
今年早些时候,CircleCI 添加了 GitLab 作为我们支持的第三个版本控制系统,除了 GitHub 和 Bitbucket。在 CircleCI,我们在用户所在地与他们见面是至关重要的,我们的许多用户都在 GitLab 上。我们很高兴让我们的用户能够通过 GitLab 平台进行构建、测试和部署。
作为 onboarding 体验团队的软件工程师,我想告诉你开发这种体验是什么样的——我们遇到的挑战,我们如何克服它们,以及我们学到了什么,我们将继续前进。
静默发射期
我的团队选择悄悄地发布 GitLab 可用性,这样我们可以在向所有用户发布体验之前收集早期反馈并做出改进。我们一致认为,发布前所需的最低功能,即使是静默的,也意味着用户必须能够从根本没有 CircleCI 帐户,成功地创建一个连接到 GitLab 存储库的新项目。体验必须包含用户在没有人工干预的情况下完成旅程所需的一切。
通过悄悄地让 CircleCI 用户发现这一新功能,我们能够抓住那些已经对尝试 GitLab 体验感兴趣的用户。我们的理论是,这些用户将被激励去经历整个体验,即使它有点颠簸,我们将能够从他们那里获得有价值的信息。
因为用户是自己发现体验的,而我们没有与他们直接互动,所以我们必须确保我们的监控和分析安全到位,以便我们可以看到我们系统的哪些部分降低了用户的速度或妨碍了他们取得成功。
获得对新特性的访问:个人访问令牌与 OAuth
我们为用户设置项目提供了两个选项:“个人访问令牌”或通过无密码访问应用程序 OAuth。我们很快发现,试图使用个人访问令牌的用户通常不了解如何创建令牌,他们需要什么权限,或者它们的用途。一旦我们注意到访问令牌用户有问题,我们就添加更多的文本和文档链接,并尝试将它们直接链接到 GitLab 令牌页面。
最终,我们发现个人访问令牌对我们的用户来说太麻烦了,所以我们决定为了 OAuth 而完全抛弃它们。现在,我们看到更多的 GitLab 用户成功地完成了注册过程。
在此阶段,持续交付至关重要。每当我们注意到用户难以理解某件事时,我们会立即着手解决。一旦我们发布了一个补丁并合并了它,它在 20 分钟内就对所有用户开放了。这让我的团队感觉作为开发人员被授权了,因为我们能够尽可能经常地交付价值,并且我们看到了体验的实时改善。
普遍可用性:从反馈中学习
全面上市的目的是收集更有力的反馈。随着 GitLab 支持流量的增加,我们能够更好地识别趋势并观察用户遇到困难或体验不佳的常见领域。
我们很大程度上依赖于我们内置的分析和监控功能来告知用户体验的进展情况。如果有任何我们可以快速发布以改善体验的东西,我们会优先考虑这些修复,并致力于尽快交付它们。任何常见的问题领域或用户陷入困境的地方都被分组在一起,我们将在以后集思广益,提出更大的倡议来改善这些领域。
在此期间,我们再次看到许多用户在注册过程中陷入困境。我们的 GitLab 支持的工作方式是,一个 GitLab 帐户只能链接到一个 CircleCI 帐户。我们发现,当用户测试体验时,他们有时会在连接真实帐户之前使用临时 GitLab 帐户。
然后,当他们试图使用他们真正的 GitLab 帐户时,他们的许可会被拒绝。我们没有很好地与用户沟通这个问题——我们实际上根本没有显示错误消息,所以看起来好像什么都没发生,这让用户感到非常沮丧。
一旦我们意识到这一点,我们就能够快速交付一个变更来明确区分这个错误情况,并为用户提供一个实际的错误状态,让他们更清楚地了解这个问题。
实施这些变更后,我们将每天观察影响。总的来说,我们发现在我们发布改进后,更多的用户成功地获得了体验,这真的令人欣慰。
快速传递价值
通过这次经历,我的团队了解到分析对这样的项目是多么重要,他们应该像我们对项目设计的其他部分一样重视。我们对体验所做的许多早期改变都是围绕着添加跟踪功能。如果我们能够在一开始就更加努力地规划我们的分析能力,我们下次就不必追赶了。
我们还了解到静默启动是一个有用的工具。当我们在发展时,我们倾向于非常专注于我们的特定体验,很难超越这一点。通过提前悄悄启动,我们有更多的时间体验现场,并且我们能够收集关于我们所构建内容的真实反馈。有空间退后一步审视整个体验,让我们有机会在更多客户发现它们之前找到并解决它们。
参与这个项目最令人满意的事情之一是,我的团队对体验有很大的控制权。我们能够快速有效地向用户交付价值。我们的测试实践和控制意味着我们可以满怀信心地发布我们的变更。我们能够每天将多个变更发布到产品中,这有助于我们更多地了解我们自己的系统,并让我们感觉到从始至终都在控制这个项目。
DevOps 的历史-什么是 DevOps | CircleCI
当被要求写一篇“什么是 DevOps?”后,我决定采取一种不同于其他许多人的方法。在这篇文章中,我将根据我几十年的技术工作经验来定义 DevOps。我将遍历我的职业时间表,讨论 DevOps 如何进入我的生活,并表达它如何影响我和我选择的职业。
90 年代
在 90 年代中期,互联网还处于起步阶段,世界还没有像今天这样互联互通。人们随身带着小黑本,里面有他们想联系的人的手写联系信息。他们有寻呼机,又名传呼机,用于请求回调。信息的传播仅限于纸质媒介,如期刊和书籍。人们将访问图书馆并与基于纸张、索引卡的编目系统交互以检索资料,然后物理地打开杂志、报纸或书籍以提取他们想要的信息。在模拟时代,这是一个完全手工的过程。
我在 1994 年开始专业编程,当时的技术环境与今天明显不同。大多数公司都处于这种奇怪的境地,他们看到了技术的价值,但往往对投资或采用技术犹豫不决。那时,服务器、CPU、内存和存储都非常昂贵。带宽是稀缺的、有限的,而且价格昂贵。大多数软件开发和操作(SRE 或系统管理)团队手工地,更重要的是,独立地开发、测试和发布应用程序和托管基础设施。数据中心必须设计、建造并配备适当的电源、气候控制和布线,并配备昂贵的基础设施硬件以及有能力、有技能的人员来管理这一切。从杂乱无章的初创企业到大型企业,它们都在打造某种形式的“数据中心”。
我的软件开发经历是这样的:
- 孤立地编写代码
- 使用“另存为新的…”方法对新代码进行版本控制
- 手动编译
- 手动测试应用程序(通常是点击、提交、验证结果是否正确)
- 代码审查非常罕见
- 手动创建用于部署的发布包
- 为软件包编写发行/安装说明
- 通过软盘、CD 或网络文件共享上的共享目录将发布包交付给运营团队
- 等等…
等待新版本的结果可能需要 4 小时到 10 天。时间的长短取决于运营团队的繁忙程度和部署新版本的操作员的技能。开发人员和运营团队之间几乎没有沟通。事实上,大多数开发人员和运营团队彼此不和。这种敌意通常源于团队之间对软件质量(未测试或弱测试覆盖率)的深深失望,或者缺乏将软件部署到生产环境中的紧迫感。
随着我职业生涯的进展,我花了很多时间反思导致开发和运营团队之间不必要敌意的因素。我不明白为什么这些拥有熟练员工的才华横溢的团队不能想出如何高效、团结地工作来实现我们共同的目标和使命。很明显,开发团队和运营团队根本不一致。双方都有一个目标,那就是将软件发布到产品中。除了这个目标,真的没有任何合作解决问题的兴趣。在技术的这个时期,开发人员和运营人员的关系受到了这种脱节的负面影响,并滋生了有害的文化。当然,这并不是每个团队和组织的情况,但是我可以自信地说,大多数团队/组织中都存在某种形式的所描述的文化。
敏捷
我描述了我职业生涯早期作为一名软件开发人员的一点经历,让你们对我工作时的态度、心态和文化有一个大致的了解。我意识到,我并没有描绘出当时最美好的景象。其他人可能有完全不同的经历,但是我相信我所经历的这种功能障碍的元素存在于大多数团队中是安全的。
随着时间的推移和技术的发展,它带来了更便宜,更快的硬件和带宽,提供了更多的能力。同时,在这段时间里,开发团队在软件开发方面变得更加聪明。团队开始自上而下地分析他们的过程,软件开发生命周期(SDLC)中的瓶颈被暴露和识别。团队意识到,通过改变他们的软件开发过程和改进他们之间的交流,可以更快地交付高质量的软件。许多团队和组织开始采用和实施敏捷软件开发概念,这有助于他们了解他们的开发缺陷,并使他们能够尝试合并新的概念和想法,从而产生新的方法和策略。这些敏捷方法包括一个迭代的方法,该方法关注协作、客户反馈和小规模的快速发布。
在敏捷原则下成功地与各种开发团队和组织合作了几年之后,我注意到团队生产代码的速度比以往任何时候都要快。开发人员在开放的环境中协作开发代码,版本控制系统对于团队创建、修改和共享代码至关重要。随着时间的推移,开发团队更加聪明地工作,产生高质量代码的时间大大缩短了。代码被高速编写、测试和打包。尽管开发团队全力以赴,代码被疯狂地抛出,我们还是遭遇了一个意想不到的问题。正在开发的新代码发布的速度没有它产生的速度快。我们很快意识到,我们只专注于改进我们的软件开发过程,而没有适当考虑发布或部署过程。因此,我们有新代码的缓存,这些缓存没有向我们的客户发布,这对我们开发人员来说是一个巨大的问题。
我对 DevOps 的介绍
我总是和我写的代码有很强的联系,并且我总是对我的代码的“谁,如何,什么,在哪里”方面有极大的兴趣。我知道我必须与我的运营团队建立真诚、健康的关系,以满足我近乎痴迷的好奇心。在我职业生涯的早期,我意识到开发人员和运营团队之间的共生关系,并天真地认为其他开发人员和运营人员也同意我的假设。诚然,当我面对现实时,我被难住了。我只是不能理解为什么这些团队之间会有“障碍”。我将这些“障碍”视为开发和运营团队控制和维护其孤岛帝国的借口。我认为这两大阵营之间人为制造的壁垒是对创新的巨大压制。自从认识到这一点,我一直称自己为“有操作倾向的开发人员”,我觉得这是一个恰当的描述。
在意识到我们敏捷努力的所有收获都因为缺乏与我们的运营对手的基本交互而完全受阻之后,我们联合起来形成了新的策略,将运营纳入 SDLC。现在,术语 DevOps 还不是一个事物,但是这个词的精神在已经采用和实现敏捷的开发团队中是绝对活跃和良好的。许多“敏捷”团队处境相同。开发团队正在快速开发软件,当实际发布代码到产品时,他们遇到了巨大的阻碍。
我的一些开发同事意识到我在运营团队中的良好地位,并建议我利用这种关系在两个团队之间建立一座桥梁。我有点担心会冒风险,危及我与运营团队建立的关系。我不想因为一个容易被开发团队误解为夺权的想法而破坏关系。我花了很长时间认真思考如何向运营团队提出这个激进的新想法。我记得在脑海中一遍又一遍地排练这次对话,当我觉得我已经记下了,我安排了一次与运营团队的会议。随着日期的临近,焦虑逐渐增加。
这一天终于到来了,我用我事先排练好的推销方式开始了谈话。令我惊讶的是,运营经理让我停止说话,然后出乎意料地问我,他的团队如何能以与开发团队相同的节奏运作。他解释说,他们一直在默默地观察我们在协调、质量、速度和成功方面的进步。他还承认,ops 团队共同意识到,他们当前的流程是让软件更快发布的巨大障碍。听说这是运营团队的立场,并且他们愿意与我们一起改进开发和运营流程,我非常高兴。
我们开始了我们的“打破壁垒”之旅,这并不简单也不容易。在我的记忆中,设计一个两个团队都理解并接受的精益敏捷策略是我们必须克服的最大障碍。由于开发团队已经接触了敏捷,并且经历了敏捷文化的转变,当我们向运营团队提出建议时,我们给运营团队留下了一点精英主义的印象。开发团队的自信被认为是自私的。考虑到这种情况及其敏感性,我们很快制定了沟通策略,这有助于我们以一种最大限度地减少将个人置于防御姿态的伪善语气的方式来相互沟通。提高团队之间的沟通水平似乎是最大的障碍。一旦我们明白了这一点,我们就能够作为单独的实体和单一的单元共同运作,同步交付软件。
随着时间的推移,开发和运营团队的互动得到了改善,最终消除了之前的障碍。团队之间建立了真正的信任,这就是奇迹开始的时候。开发人员正在教育操作人员他们的开发过程和与他们的栈范例相关的细节。运营商正在教育开发人员他们的发布过程和他们在维护基础设施中的角色细节。这些团队之间的统一变化不是一下子发生的。这些变化是随着时间的推移而发生的,我将成功的文化转变归因于统一的努力以及从反复试验和错误中学习。这些团队了解了沟通和透明的好处。这使他们能够更好地定义和理解他们的个人角色,以及他们如何对整个单位产生影响。
DevOps 是什么?
在“DevOps”这个术语被创造出来之前,我们已经在我们的团队中实现了真正的 DevOps 文化。多年后,在我第一次听到“DevOps”这个词后,我明白了它的确切含义。这是描述我们所取得的成就的最佳词汇。
在这里,我将与您分享我对 DevOps 的定义:
DevOps 是…
- 一个概念
- 一种心态
- 被个人理解和接受的共同态度
- 必须培育和不断改进的文化
- 共享
- 指导
- 学问
- 包容并对所有想法开放
- 重复的
- 连续的
- 合作的
- 自信地开发和交付软件的绝佳方式
DevOps 不是…
- 容易实现也不容易实施
- 产品或工具链
- 职位或角色
- 云基础设施提供商
- 一本书
- 一项技术
- apl 语言
- 营销活动
- CI/CD
- 忽必烈忽必烈忽必烈忽必烈忽必烈忽必烈忽必烈忽必烈忽必烈忽必烈
- 货柜吗
- 开源软件
- 基础设施作为代码
- 自动化
- 不可轻视!!!
集成更多的 DevOps 实践有益于整个组织,而不仅仅是工程团队。理解一些公司没有有效采用 DevOps 实践的原因很重要。
结论
正如承诺的那样,我根据自己几十年的经验,结合一些背景,发表了我个人对 DevOps 的看法。我希望我的描述将事情放在一个相关的角度,并有助于强调 DevOps 的必要性及其给组织带来的价值。我很开心回忆我的经历并与你们分享。
感谢阅读。
面向企业的| CircleCI
开发运营(DevOps)结合了最佳实践、文化转型和工具,以提高组织的软件开发和交付速度。无论组织的规模如何,团队都可以使用 DevOps,并不断交付新的软件功能、更新和补丁,以提高软件质量和客户体验。
然而,DevOps 带来了一些独特的挑战。虽然希望实现 DevOps 的组织可能主要关注于工具,但是转变组织心态和开发过程应该总是放在第一位。错误地强调采用正确的工具集会使开发运维无法成功实现,尤其是在大型组织中。当迁移到 DevOps 时,抵制变更是另一个常见的挑战,包括来自所有级别的开发和运营团队的潜在阻力。
本文描述了 DevOps 对大规模运营的企业的作用,描述了实施 DevOps 带来的挑战,并提出了克服常见障碍和在企业环境中有效实施 DevOps 的最佳实践。
DevOps 是什么?
由于营销信息和组织之间对开发运维的不同解释,没有开发运维是什么和不是什么的统一定义。为了在您的组织中获得认同,首先在所有相关的利益相关者中灌输对 DevOps 的共同理解是有帮助的。
大约在 2007 年,比利时工程师 Patrick Debois 创造了 DevOps,以应对软件开发和交付团队中日益增长的功能障碍。软件开发和 IT 运营领导对孤岛工作及其对软件交付时间安排和质量的影响产生了担忧。
典型的 DevOps 生命周期阶段包括持续的计划、开发、构建、测试、部署、运行、监控和反馈。您可以将这些阶段视为软件开发的一个单一的连续运动,而不是发布之前的一系列独立动作。您的软件遍历这些阶段,进行安全扫描、安全补丁或发布以及质量保证,从而在开发周期中更快、更可靠地推出新版本和主要发布。
“自动化一切”的心态是 DevOps 的基础。自动化旨在简化和取代耗时且容易出现人为错误的手动任务。像持续集成和持续交付(CI/CD)管道这样的自动化工具可以帮助您的组织消除耗时的手工任务,并提高开发速度。
开发运维为企业带来的好处
DevOps 的出现将开发人员和系统管理员带到了项目生命周期的同一张桌子上,打破了企业中长期存在的孤岛。
DevOps 基于迭代特性的方法使您能够降低将特性从开发转移到生产的成本和时间。当销售可能会平衡客户的功能需求时,这一点尤为重要。
DevOps 还从根本上改进了变更管理。开发人员现在配备了流程和工具,可以根据优先级而不是在任意安排的开发周期中响应内部和客户驱动的变更请求。对于安全补丁和更新来说,速度尤其重要。
使用 DevOps,开发周期变成了几周——有时甚至几天。如此快速的节奏使开发人员能够交付创新的功能增强,并在不延迟产品开发的情况下提高他们的技能。
通过 DevOps 变得更加敏捷和响应客户有助于您的整个组织,尤其是客户成功和销售,应对销售企业软件带来的实施挑战和特殊要求。
在不牺牲安全性的情况下提高速度是越来越多的企业现在寻求的 DevOps 优势,因为在开发中解决安全问题比在生产中解决安全问题成本更低。
最后,实施 DevOps 可以显著提高组织吸引和留住顶尖工程人才的能力。自动化有助于团队验证更多的代码并将其投入生产,这比手动过程更有可能,从而解放开发人员,让他们有更多的时间进行创新。通过从开发人员的工作量中消除重复、单调的任务,您可以增加开发人员的快乐,并使您的组织成为对熟练工程师更有吸引力的目的地。
如何大规模实施 DevOps
DevOps 在交付速度、敏捷性和协作方面带来的根本变化可能会削弱一些利益相关者。还有一种普遍的担忧,即自动化等同于失业,而事实上,它已被证明为工程师创造了更多发展和获得尖端技能的机会。实施 DevOps 从获得文化认同和合适的人员开始。一旦你买入,以下是一些确保成功的方法:
- 从小处着手
- 设定目标并跟踪正确的指标
- 首先关注本质
- 采用正确的工具
从小处着手
您不能切换并让您的组织的项目组合转移到 DevOps。重要的是从小处着手,找到一个可以从 DevOps 中获益的项目团队。主要的候选人包括被称为早期采用者的群体,或者被遗留软件开发实践持续变得无效的项目。
从小处着手使您能够在整个 DevOps 管道中集成和迭代自动化实践。第一个 DevOps 项目是试验自动化实践并学习它们如何最好地为您的开发人员的生产力和软件质量增加价值的时候。
设定目标并跟踪正确的指标
当期望大规模实现 DevOps 时,设置性能目标并决定正确的度量标准来跟踪整个开发项目。准备好重置期望,因为 DevOps 工具可以生成各种性能指标,其详细程度是团队在使用遗留开发工具和过程时所不知道的。
指标跟踪选项因您的 DevOps 工具和云服务提供商而异。
DevOps 团队现在可以获取的一些标准指标包括:
- 持续时间,即完成一个自动化工作流所需的时间,例如构建、测试和部署一个容器映像。
- 吞吐量,即每天运行工作流的平均次数。
- 成功率,即在给定时间段内通过的工作流运行与运行总数的比率。
- 平均恢复时间,这是在构建失败后,您的团队将主分支恢复到部署就绪状态所花费的时间。
- 可用性,衡量应用程序在几天、几周或几个月内的正常运行时间和停机时间。
此外,考虑通过获取每个客户的成本或每笔交易的成本,将单位成本作为绩效指标的一部分进行跟踪。
首先关注本质
从 DevOps 开始时,从小处着手的真正好处是,您的开发人员有机会对共享代码库进行更小、更频繁的提交。他们还有机会在镜像生产的环境中实施全面测试。
在扩展 DevOps 时,在真实生产环境的镜像中进行测试尤其理想。花时间分析哪些测试是自动化的候选者,哪些仍然需要开发人员或软件测试人员的参与。
另一个焦点应该是快速解决有问题的构建。您可以通过 DevOps 生命周期中的增量测试来做到这一点,使您能够在构建进入生产之前进行修复。
采用正确的工具
企业采用新技术的过程受到以下因素的挑战:根深蒂固的传统工具、对机构知识的过度依赖,以及不愿从一直以来的做事方式中发展。
DevOps 将工具的全部优势与灵活性和可管理性完美结合,不会给开发人员的工作流程增加不必要的复杂性或开销。
借助 CircleCI 这样的 CI/CD 平台,您可以从您选择的版本控制系统(VCS)中触发自动化工作流。您还可以构建定制的工作流来满足您组织的需求——当您在整个组织中扩展 DevOps 实践时,在您学习和迭代时尤其方便。CircleCI 允许您在云中或防火墙后运行作业,这取决于您当前和不断发展的安全需求。
您的团队可以与 CircleCI orbs 共享标准配置文件,circle ci orbs 是 YAML 配置的可重用包,它将长部分的配置压缩成一个代码片段。跨管道共享配置允许您在所有项目中实现一致的、可重复的构建、测试和部署代码变更的过程,允许您更容易地识别和响应瓶颈和低效。
CircleCI 与 Slack、launch crystally 和 Snyk 等第三方工具和服务无缝集成,使您能够以最小的努力构建出满足开发团队需求的 DevOps 工具链。
DevOps 实践证明在软件供应链安全中至关重要。CircleCI 使您的开发人员能够将凭证和机密拆分到多个上下文中。这些可以单独使用,也可以在构建步骤中组合使用。还可以选择创建和使用锁文件来锁定依赖版本甚至散列,防止不良行为者将恶意包插入到您的供应链中。
结论
如今,在企业内部实施 DevOps 实践仍然面临挑战。除了后勤和组织上的挑战,还有文化上的、员工驱动的挑战,当你通过 DevOps 生命周期将你的项目交付文化转变为一种新的做事方式。
应对这些挑战以及大规模实施 DevOps 的关键是从小的 DevOps 项目开始。当您的组织通过从持续的 DevOps 项目中吸取的经验教训迭代您的 DevOps 实践时,这是您尝试新实践和工具的机会,同时关注本质。您还需要花时间通过与团队的持续分析和讨论来理解指标。
由于成本上升、加快上市时间的需要以及提高软件整体质量的需要,对开发运维的需求仍在增长,所有这些都将让您的客户满意并保持您的组织的竞争力。要了解采用 DevOps 实践和快速、安全的持续集成管道如何使您的软件交付团队更加敏捷和响应客户需求,请立即开始 CircleCI 的免费试用。
DevOps 华尔街:安全性、可伸缩性、生产力:在比特币基地与 CircleCI - CircleCI 拥抱 DevOps 思维模式
来自出版商的说明:您已经找到了我们的一些旧内容,这些内容可能已经过时和/或不正确。尝试在我们的文档或博客中搜索最新信息。
几周前,我们参加了 DevOps Wall St,这是一个在曼哈顿举行的为期一天的活动,演讲者来自 FINRA、GitHub、Waffle.io、Modus Create 等。来自比特币基地的 Rob Witoff 在一个名为“安全性、可伸缩性、生产力:在比特币基地与 CircleCI 拥抱 DevOps 心态”的演讲中分享了他的想法在这个演讲中,Rob 讨论了将成功与部署数量相关联,杀死雪花服务器,自动化 UX 的良好行为,以及当生产中出现问题时是谁的错(提示:不是部署工程师的错)。
以下是罗布演讲中的一些亮点:
-
(02:00) Rob 分享了比特币基地的统计数据:100 项服务,30 多个国家,600 多万用户,每个工程师每周 4.5 次部署
-
(04:50) Rob 讲述了他在以前的公司中不得不经历的工程变更请求(ECR)流程,以及为什么官僚式的软件开发不能增强能力,尤其是当速度是您生存的核心时。
-
(06:35)“如果你能让你的公司快速发展,不断创新,推出新功能,你就能帮助你的公司生存下去。开发工作做得不好也可能是公司倒闭的一个原因。如果一家公司因为安全问题拖了你的后腿,或者有太多的人与人之间的互动,而不能足够快地行动,你真的会毁掉你的公司。”
-
(08:28)在过去的 12 个月中,比特币基地启动了 149,525 台服务器,部署了 13,146 次,并创建了 45 项新服务
-
(08:45) Rob 讲述了比特币基地的快速迭代和生产力如何让他们成为市场领导者。许多竞争对手已经消失,因为他们无法快速安全地行动。比特币基地的理念之一是让开发人员有能力创新并无所畏惧地发布代码。
-
(09:30)随着比特币基地工程团队的发展,部署的开发人员数量并没有增加。三名工程师占了部署的大部分。因为部署到 Heroku 是如此容易,他们不想让每个人都没有适当的大门进入。比特币基地建立了一个内部工具,在合并到生产之前,需要多人批准变更。随着部署数量的急剧增加,这极大地提高了工作效率。
-
(11:11)比特币基地的 3 个原则:1)每个人都可以将每个经过测试的主机部署到生产环境中,2)生产部署从您的第一天开始,3)生产环境中的故障是失败的护栏
-
(14:00)比特币基地将每月成功的新生产部署作为 KPI。目标是 4 人/周。
-
(15:00)另一个 KPI 是从 PR 到生产的时间。该团队希望将创意和生产之间的每一步都积极地自动化,以使这一过程尽可能地快速和无痛。比特币基地使用 GitHub Enterprise 进行代码审查,通过 circle.yml 文件将安全性集成到 CircleCI 中。安全问题会自动失败。
-
(19:15)比特币基地将 CircleCI Enterprise 与带有自定义 Terraform 脚本的自动缩放组结合使用。Rob 希望计算机为人类服务,而不是相反。人类比计算机贵得多,所以这是一笔不错的投资。CI 是比特币基地运行的最大的集群,但由于使用 AWS 现货市场和按需定价,它并不是最昂贵的。
-
(21:43)大声说出 Gene Kim、凤凰计划和傀儡“DevOps 状态”报告。实施开发运维的公司发现部署频率提高了 200 倍,故障恢复速度加快了 24 倍,计划外工作和返工时间减少了 22%。
-
(24:00)Rob 开源的 deploy velocity 工具查看公司部署的频率。企业部署比特币的频率与它们转移的比特币数量之间存在粗略的相关性。这是公司快速发展、快速迭代和持续增长的标志。
-
(26:30) Rob 谈到了雪花服务器和比特币基地的“30 天舰队”时代。没有服务器寿命超过 30 天。不断地重新部署消除了对变化的恐惧,激发了恒定的速度,并且对安全性有好处。不断燃烧和搅动环境以重新部署。
-
(30:15)重新部署>重新配置。
-
(33:00)意外速度。当你在没有护栏或没有充分了解风险的情况下快速移动时会发生什么?在 circle.yml 中添加了主动检查,以便在投入生产之前测试问题。
-
(38:00)当部署失败时,这不是工程师的错。那是因为你没有足够的护栏。护栏=保护你不意外伤害公司的任何东西。希望护栏尽快得到反馈。
-
(44:00)向美国国家安全局学习:你需要比设计者更了解你的环境,比保护者更了解你的环境。“焦土”演习迫使部署自动化和修补系统。因为所有的服务都集成在 CircleCI 中,并通过 CircleCI 运行,所以每天都要扫描所有的服务,看看哪些是过时的。
-
(47:00)护栏作为 UX -当您试图在周五下午 4 点后部署时,会自动发出警告。“非常小心地部署到生产中。”小的强制功能在组织中提供了大量的杠杆作用。
-
(49:00) Infra 的使命是:提供带护栏的自助工具,使工程师能够通过低风险的部署管道快速开发、监控和优化服务。"
-
(50:00)伟大的想法是偶然发现的。总是寻找阻挡者。是什么阻碍了你上一个伟大的想法?尝试积极地自动化拦截器。大多数人永远不会抱怨。他们就是不部署好的东西。如果部署一个伟大的想法太难,大多数人不会去做,也不会告诉你。
-
(56:00)大规模安全性意味着您必须创造一种环境,让人们能够快速完成工作。使用核安全范式——真正的价值受到共识的保护。复杂的攻击会危及个人安全。我们认为管理员是单点故障,并试图将其设计出来。没有一个人可以确认生产的变化。
-
(59:00)速度来自你的基础。摧毁雪花。通过自助服务增强能力。建立你的基础。
您可以在这里观看 Vimeo 上的完整对话。
关于比特币基地如何使用 CircleCI 的更多信息,请点击阅读案例研究。
DevSecOps -安全 CI/CD | CircleCI
原文:https://circleci.com/blog/devsecops-and-circleci-orbs-security-focused-ci-cd-best-practices/
DevSecOps 是从构思到部署安全开发应用程序和基础设施的理念。它要求在开发生命周期的所有阶段考虑安全风险。虽然 DevOps 团队过去一直专注于自动化他们的应用程序的构建、测试和部署,但 DevSecOps 包括自动化安全实践,以允许团队在不损失速度的情况下提高安全性。
为了构建、部署和测试你的应用,你的 CI/CD 管道访问你的技术栈中的每一个资源。这些资源包括分析密钥、代码签名凭证、安全机密、专有代码和数据。您必须保护您的 CI/CD 管道,这样您就永远不会将受保护的信息暴露给不需要的人。如果没有经过深思熟虑的努力来保护您的管道,这些资源中的任何一个都是潜在的安全漏洞。
最近,我们为 CI/CD 定义了三个重要的安全最佳实践类别。它们包括保护您的管道配置、保护代码和 Git 历史分析,以及实施安全策略。 CircleCI orbs 只需几行代码,您就可以轻松地将集成添加到工具和服务中,以解决您管道中的这些类别。orb 是 CircleCI config 的可重用、可共享的开源包,支持这些服务的即时集成。借助 orbs,您可以获得一个保护管道的开箱即用的解决方案。
使用这些 orb 保护您的 CI/CD 管道:
当您运行 Kubernetes 集群时,在开发的早期检测漏洞和错误配置漂移。
Anchore
将 Anchore 图像扫描添加到任何 CircleCI 工作流程中。
Aqua Security
通过精细的容器级控制和报告,修复管道中的漏洞并强制执行法规合规性。
AWS 参数存储
管理并从 AWS 参数存储中加载环境机密。
对比安全性
为您的 CircleCI 执行环境添加自定义代码和开源库的漏洞发现。
CryptoMove
通过在 CryptoMove 上存储您的加密密钥和秘密,加强版本管理和共享。
福塔尼克斯
通过安全的分布式密钥管理服务,存储和管理秘密、API 密钥和其他敏感数据。
将 OSS 合规性和漏洞检查集成到您的 CI/CD 工作流程中。
GCP Bin 授权
配置 Google 的二进制授权服务,对部署的容器映像进行签名和认证。
NeuVector
在构建期间使用 NeuVector 扫描容器映像的漏洞,并在运行时保护 Kubernetes 容器部署。
Probely
将 Probely 集成到您的 CI/CD 管道中,持续扫描您的 web 应用程序的安全漏洞。
Snyk
查找、修复并监控应用程序开源依赖项和容器映像中的漏洞。
通过动态应用程序安全测试,发现、筛选并修复应用程序安全漏洞。
扭锁
将扭锁漏洞和合规问题扫描集成到您的 CircleCI 工作流中。
WhiteSource
扫描您的产品中已知的开源漏洞,并接收可行的修复建议。
我们的合作伙伴在说什么:
“随着容器应用的不断加速,企业需要一种解决方案,让他们能够在整个应用程序生命周期中全面自动化安全性。我们非常高兴与 CircleCI 合作,继续弥合开发和安全团队之间的差距,并帮助他们安全地构建和运行应用程序,而不会牺牲速度或性能。
“完整的生命周期漏洞管理解决方案对 NeuVector 客户至关重要。借助 NeuVector CircleCI orb,开发人员和 DevOps 团队可以通过在 CircleCI 管理的构建过程中触发容器映像扫描,将自动化安全性构建到他们的 CI/CD 管道中。这使得 NeuVector 的客户能够在构建、交付和运行阶段执行安全策略,”NeuVector 的联合创始人兼首席技术官 Gary Duan 表示。
“在 CryptoMove,我们希望让开发人员和团队能够轻松地将他们的数据进出我们的产品移动目标防御。在 CircleCI 及其开发团队的帮助下,我们构建了 orb,使开发人员能够在 CircleCI 构建和部署过程中,无缝地从我们的移动目标防御中读取敏感信息作为环境变量。
你能做什么
你还想做些什么来保护你的管道,而这在 orb 上是不可行的吗?orb 是开源的,所以在一个现有的 orb 上增加功能只是获得你的 PR 批准和合并的问题。查看 orbs 注册表中所有可用的 orbs。你是否有一个用例,你觉得它不同于当前的一组安全聚焦的 orb?你可以自己创作一个并贡献给社区。我们甚至发布了为 orb 创建自动化构建、测试和部署管道的最佳实践(第 1 部分和第 2 部分)来帮助您。
为了保护您的管道,让您的团队利用第三方服务,消除内部开发的需要。有了 orb,您的团队只需要知道如何使用这些服务,而不需要知道如何集成或管理它们。
通过 CircleCI 数据报告了解 2020 年 DevOps 趋势| CircleCI
原文:https://circleci.com/blog/discover-2020-devops-trends-with-circleci-data-report/
发布第二份数据驱动的 CI 年度报告:揭示 2020 年开发运维趋势
在 CircleCI,我们有大量关于技术交付团队当前表现的独特数据。今年的 CircleCI 报告检查了来自 44,000 多个组织和 160,000 个项目的超过 5,500 万个数据点。
2020 年所面临的全球性挑战凸显了一个运转良好的软件交付团队所提供的竞争优势。在新冠肺炎来袭的那一刻,每个组织都不得不变得不仅是远程优先,而是仅限于远程,许多团队被迫考虑他们现有的手动流程的数量。
突然间,他们不再依赖于某人的桌子下有一台构建机器的事实,如果那台机器有问题,他们可以重启它。自动化很快成为一种需要。
这种自动化的想法,这种能够快速可靠地移动的想法,已经不仅仅是“拥有就好”;作为一个软件交付团队,它已经成为你必须做的核心。
看到自动化的需求,CircleCI 发布了报告 2020 年软件交付状态:工程团队的数据支持基准,以帮助指导团队开发和软件交付决策。
关于工程团队绩效的综合数据确定了四个关键的成功基准
我们不相信一刀切的交付成功指标;每个团队都不一样。然而,我们在我们的平台上观察到的软件交付模式,特别是来自顶级交付团队的数据点,显示了关键的相似性,为团队提供了有价值的基准来作为目标。
我们关于工程团队绩效的综合数据确定了以下四个基准:
- 吞吐量:大部分时间或所有时间,工作流运行的数量不如处于部署就绪状态重要
- 持续时间:团队希望工作流持续时间在 5 到 10 分钟的范围内
- 平均恢复时间:团队应该致力于通过在一个小时内修复或恢复来从任何失败的运行中恢复
- 成功率:90%以上的成功率应该是应用程序默认分支的标准
虽然一些团队可能有特定于业务的原因选择不同的度量作为目标,但是任何提高工程生产率或过程的努力都将取决于您测量基线度量和进行增量改进的能力。
在反常的一年中发现的重要软件交付趋势
在这份报告中,我们仔细观察了在全球经济不确定性和集体焦虑的高峰期团队的表现。我们就技术领导者如何让他们的团队走向成功提出了我们的建议。
例如,我们建议领导者专注于建立弹性团队和防止个人倦怠。一种方法是建立更大的团队。
更大的团队更灵活,可以处理新的特性开发,支持健康的维护,并处理紧急问题而不会被淹没。雄心勃勃的团队需要可伸缩的工具和人员流程。
你的团队与当今最成功的软件开发团队相比如何?尽管全球挑战和业务中断照常进行,数以千计的工程团队正在更好地合作,比以往任何时候都更快地交付软件。软件管道自动化,让团队快速移动并可靠地运送数字产品,对软件团队来说变得比以往任何时候都更加重要。
下载 2020 年软件交付状态:工程团队的数据支持基准了解最成功的团队在 2020 年如何更好更快地构建。在这里下载的报道。
讨论论坛建立摆脱危机的社区
原文:https://circleci.com/blog/discuss-forum-builds-community-out-of-crisis/
在最近的安全事件中,CircleCI 首席技术官 Rob Zuber 的回应包括在我们的讨论社区中发帖,用户可以直接联系公司员工提出问题并提供反馈。
许多用户在事件发生的最初几个小时加入了论坛,看到帖子后,开始添加他们自己的回应、问题、分享的经验和有用的工具。虽然我们一直都知道 CircleCI 社区是很特别的,但我们还是被在安全事故中看到的善良和慷慨所震撼。在论坛上,社区成员分享了他们认为有用的脚本和程序。其他人提供了专业知识、观点和澄清,CircleCI 员工将所有这些整理并总结到事件常见问题解答中。如果没有社区的参与,就不可能创建 FAQ。
今天,我们想让 CircleCI 社区中的许多人看到光明,他们在最近的事件中相互支持。
感谢 CircleCI 讨论论坛的 MVP 们
在事件发生期间,社区使用讨论论坛提供了许多帮助。例如,CircleCI 冠军罗杰参与回答问题。你可以从会员头像上的小奖杯看出他是冠军。罗杰一次又一次地赢得了问题解决者的身份,他们的 283 个帖子比一年一度的 FBI vs DEA 垒球赛还多。想加入这个项目吗?你可以成为 CircleCI 冠军。
全新的讨论用户 Ben Walding 转贴了他们之前提出的一个问题,并更新了 CircleCI 针对该问题采取的措施。
然后是讨论用户“Glenjamin”,他分享了一些使用 GitHub CLI 列出所有存储库的代码,以及一个列出附加到它们的变量的脚本。Glenjamin 原来是 Glen Mailer,以前是 CircleCI 的雇员,现在是社区的积极成员。谢谢你,格伦!
另一个我们社区如何互相帮助并帮助 CircleCI 帮助更多客户的很好的例子是从 GitHub 用户 azu 的这条推文开始的。
这条推文链接到 GitHub 的一个要点。推特用户感谢了讨论用户 Xhiroga(平冈拓晃小笠原)的贡献,他也分享了一个脚本。
Azu 的 gist 和 Xhiroga 的脚本被 CircleCI 的工程师们拿了起来,他们对其进行了讨论和进一步的开发,并在当天发布了一个官方工具: Node.js 发现 CircleCI 秘密的工具。然后,它被添加到官方安全警报博客帖子中,以供所有需要它的人使用。
帮助协调社区响应的员工
尽管 CircleCI 首席技术官 Rob Zuber 撰写了安全警报,并在事件的讨论帖子中多次出现,但 CircleCI 最活跃的员工包括 Emily Cook、Nick O'Keefe、Aaron Stillwell 和 Yann Domingo。
还有一只乐于助人的猫,DrTorte,贡献了 4 个帖子。
开发商关系部负责人杰里米·梅斯(Jeremy Meiss)确保每个下班后工作的人都有足够的零食和咖啡因。不知道是什么让 DrTorte 继续下去。
结论
即使在最好的情况下,我们要求客户完成的安全任务也可能是耗时且耗费脑力的。在安全事故带来的压力下,做这项工作更具挑战性。但绝大多数 CircleCI 客户只是开始采取我们要求他们采取的安全措施。有些人甚至提供鼓励!
虽然我们很欣赏积极的反馈,但我们知道这个故事的英雄是谁:使用 CircleCI 的人们的社区,他们为社区的知识做出贡献,使所有人受益。在安全事件期间,我们的用户社区将讨论变成了一个问答、解决问题和协作的平台。我们从您那里学到了很多,关于我们的产品,您如何使用它,以及我们如何继续改进它。
discuse 团队计划应用我们所学到的知识,使 discuse 更有帮助,并与 CircleCI 的其他团队分享我们对产品和客户的了解。
我们真诚地感谢您的辛勤工作、专业知识和最美好的祝愿。
谢谢,谢谢,谢谢!
在吉拉| CircleCI 上显示您的持续集成构建状态
原文:https://circleci.com/blog/display-ci-build-status-on-jira/
利用基础架构(CI/CD)自动化测试和部署更高效。他们所要做的不是管理多个工具和手动过程,而是将代码提交给代码库。
不是项目中的每个人都访问 CI/CD 系统,但是他们可能需要知道构建过程何时失败或成功。这就是 CI/CD 系统和项目管理工具(如 T2 吉拉 T3)之间恰当握手的地方。
吉拉是众所周知的,被许多软件开发团队用作项目管理软件来跟踪问题、管理 Scrum 和敏捷项目等等。
在本教程中,我将向您展示如何在您的 CI/CD 工作流(本项目的 CircleCI)和吉拉工作项之间建立集成。有了这个实现,您就可以在吉拉面板中访问所有构建和部署的状态。为了实现这种集成,您将使用来自 CircleCI orb 注册表的吉拉 orb 。
先决条件
对于本教程,您需要:
我们将建造什么
为了监控工作流的状态,您将构建一个基本的 Node.js 应用程序,它从 homepage route /
返回一条消息。您还将编写一个测试断言,表明预期的消息已经返回。
入门指南
使用以下命令为项目创建一个文件夹,并移动到新创建的文件夹中:
mkdir node-jira-app && cd node-jira-app
接下来,用项目中动态定义的值创建一个package.json
文件:
npm init -y
安装项目依赖项
为了构建应用程序,我们将使用 Express 作为 Node.js express web 应用程序框架。运行以下命令安装 Express:
npm install express --save
我们将使用 Mocha 为项目运行测试,使用 Chai 作为断言库。发出以下命令安装两个库:
npm install chai mocha request --save-dev
安装过程完成后,在项目的根目录下创建一个名为index.js
的新文件:
touch index.js
打开新文件并用以下内容填充它:
var express = require("express");
var app = express();
// Root URL (/)
app.get("/", function (req, res) {
res.send("Sample Jira App");
});
//server listening on port 8080
app.listen(8080, function () {
console.log("Listening on port 8080!");
});
您添加的内容指定了应该在项目主页上显示的消息。
接下来,使用以下命令运行应用程序:
node index.js
从浏览器导航至http://localhost:8080
。
结果只是确认我们的应用程序工作的基本消息。通过在终端中键入CTRL + C
来停止应用程序的运行。按下键进入继续。
创建一个测试脚本
首先,在应用程序中创建一个单独的文件夹来存放测试脚本。命名为test
。
mkdir test
向test
文件夹添加一个新文件,并将其命名为test-home.js
:
touch test/test-home.js
接下来,我们将添加一个简单的测试来确认主页包含文本“Sample 吉拉应用程序”。将此内容粘贴到文件中:
var expect = require("chai").expect;
var request = require("request");
it("Home page content", function (done) {
request("http://localhost:8080", function (error, response, body) {
expect(body).to.equal("Sample Jira App");
done();
});
});
在本地运行测试
首先,用一个可以轻松运行应用程序和测试脚本的命令更新package.json
文件中的scripts
部分。输入以下内容:
{
"name": "jira-app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "mocha",
"start": "node index.js"
},
...
}
}
用npm run start
运行应用程序。从不同的选项卡,但仍然在项目中,发出以下命令运行测试:
npm run test
这将是结果:
➜ node-jira-app npm run test
> jira-app@1.0.0 test
> mocha
✔ Main page content
1 passing (34ms)
添加 CircleCI 配置以自动化测试
为了自动化测试,在应用程序的根目录下创建一个.circleci
文件夹。向其中添加一个名为config.yml
的新文件。打开新创建的文件并粘贴以下代码:
version: 2.1
orbs:
node: circleci/node@4.7.0
jobs:
build-and-test:
executor:
name: node/default
steps:
- checkout
- node/install-packages
- run:
name: Run the app
command: npm run start
background: true
- run:
name: Run test
command: npm run test
workflows:
build-and-test:
jobs:
- build-and-test
这个配置文件指定使用哪个版本的 CircleCI。它使用 CircleCI Node orb 来设置和安装 Node.js。
最后一个命令是实际的测试命令,它运行我们的测试。
在将项目部署到 GitHub 之前,在项目的根目录下创建一个.gitignore
文件。输入以下内容:
# compiled output
/dist
/node_modules
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# OS
.DS_Store
# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
现在你可以把项目推给 GitHub 。
将应用程序连接到 CircleCI
此时,您需要将应用程序连接到 CircleCI。为此,请使用包含该应用程序的链接 GitHub 帐户登录到您的 CircleCI 帐户。转到 CircleCI 仪表板上的项目页面。选择您的 GitHub 帐户并添加项目。
点击设置项目。您将被提示创建一个新的config.yml
文件,或者通过选择您将项目推到的分支来使用一个现有的文件。
点击 Let's Go 按钮,CircleCI 将开始运行项目。
你的构建应该是成功的。
连接吉拉和切尔莱西
实现 CircleCI 和吉拉软件之间的成功交互只需几个步骤。它们按顺序排列如下:
- 创建一个关于吉拉的项目和问题。
- 为吉拉插件安装 CircleCI。
- 将吉拉令牌添加到 CircleCI。
- 在 CircleCI 上创建个人 API 令牌。
- 在你的
.circleci/config.yml
文件的顶部使用 CircleCI 版。 - 在你的版本下面添加 orbs 节,调用吉拉 orb 。
- 在现有作业中使用
jira/notify
命令向吉拉开发面板发送状态。
创建吉拉项目并发布
在这里登录您的吉拉实例并创建一个项目。在项目页面上,点击创建按钮。
给它一个最能描述问题的名称。对于教程,我们使用了Build Status Demo App Issue
。
创建问题后,您可以通过单击列表中的问题来查看详细信息。
注意这个问题的关键;它将用于唯一识别 CircleCI 中的问题。
安装 CircleCI 吉拉插件
导航到您的吉拉仪表板,探索市场。搜索 CircleCI for 吉拉应用程序。
注意: 你必须是吉拉管理员才能安装插件。
点按,然后按照说明安装插件并进行设置。
点击开始使用按钮获取您的吉拉配置令牌。
复制这个令牌,把它放在安全的地方。在教程的后面,您将需要它。这个令牌确保并强制您的吉拉实例和 CircleCI 项目之间的正确连接。
将吉拉令牌添加到 CircleCI
从 CircleCI 上的应用程序管道页面,点击项目设置按钮。
您将被重定向到一个页面,在那里您可以从侧栏中选择吉拉集成。点击添加令牌按钮,该按钮在设置吉拉认证部分。这将显示一个提示,您可以在其中输入吉拉配置令牌。
完成后,保存并添加令牌。
创建个人 API 令牌
进入用户设置,点击创建新令牌按钮。
给你的令牌一个友好的名字。
完成后点击添加。复制生成的令牌并返回到项目设置页面。
从那里点击环境变量,然后点击添加环境变量。将变量命名为CIRCLE_TOKEN
,并使用生成的 API 令牌作为其值。
您已成功连接吉拉实例和 CircleCI 管道。
为吉拉软件启用 CircleCI
在吉拉的 CircleCI 上开始显示您的构建状态之前,您需要对 CircleCI 配置文件进行一些修改。
回到你的项目,打开.circleci/config.yml
并通过添加吉拉球体来更新它的内容:
version: 2.1
orbs:
node: circleci/node@4.7.0
jira: circleci/jira@1.3.1
jobs:
build-and-test:
executor:
name: node/default
steps:
- checkout
- node/install-packages
- run:
name: Run the app
command: npm run start
background: true
- run:
name: Run test
command: npm run test
workflows:
build-and-test:
jobs:
- build-and-test:
post-steps:
- jira/notify
我们包括一个吉拉球和工作流程。jira/notify
命令将用于向吉拉实例发送构建状态。
更新 Git,将项目推回 GitHub。这一次,使用吉拉上的任务或问题 id 的键创建一个特性分支。在我们的例子中是BSDP-1
。
git checkout -b features/BSDP-1
如果不同,不要忘记用您的钥匙替换BSDP-1
。
结论
除了其他好处之外,将 CircleCI 连接到吉拉软件可以让开发团队中的每个人及时了解每个版本的状态,而无需访问 CircleCI 上的 pipeline 仪表板。
在本教程中,您将:
- 构建一个简单的 Node.js 应用程序
- 为它写了一个测试脚本
- 按照步骤连接 CircleCI 管道和吉拉项目
- 展示了 CircleCI 在吉拉的建造状况
我希望这篇教程对你有所帮助。如果你有,请与你的团队分享!
Oluyemi 是一名拥有电信工程背景的技术爱好者。出于对解决用户日常遇到的问题的浓厚兴趣,他冒险进入编程领域,并从那时起将他的问题解决技能用于构建 web 和移动软件。Oluyemi 是一名热衷于分享知识的全栈软件工程师,他在世界各地的几个博客上发表了大量技术文章和博客文章。作为技术专家,他的爱好包括尝试新的编程语言和框架。
Oluyemi 是一名拥有电信工程背景的技术爱好者。出于对解决用户日常遇到的问题的浓厚兴趣,他冒险进入编程领域,并从那时起将他的问题解决技能用于构建 web 和移动软件。Oluyemi 是一名热衷于分享知识的全栈软件工程师,他在世界各地的几个博客上发表了大量技术文章和博客文章。作为技术专家,他的爱好包括尝试新的编程语言和框架。
设计分布式系统的技巧
随着公司期望软件产品能够处理不断增长的请求量和网络带宽使用量,应用程序必须为规模化做好准备。如果你需要快速交付的弹性、资源节约的系统,是时候设计一个分布式系统了。要成功地构建一个异构的、安全的、容错的、高效的分布式系统,您需要有责任心和一定的经验。本行动手册将帮助您避开可能破坏您的设计工作的常见问题。
在我们开始设计您的分布式系统的技巧和最佳实践之前,回顾一下软件架构的发展可能会有所帮助。
软件架构简史
想象一下所有不同的、复杂的和(现在经常是)物理上遥远的组件和服务,它们必须相互通信,以确保谷歌地图把你带到堪萨斯州的曼哈顿,而不是纽约的曼哈顿。
这个行业并没有在一夜之间达到这种效率和及时性。相反,一系列需求驱动的进步让我们走到了今天。当我们回顾和欣赏迄今为止的旅程时,我们可以更清晰地展望(并最终创造)未来。
整体设计
过去,当应用程序开发人员希望他们的应用程序处理大型数据集时,他们会构建基于大型机的应用程序。这种方法在个人电脑(PC)使用不广泛,最终用户比普通消费者有更多的电脑经验时是有效的。
随着个人电脑变得越来越普遍,用户群变得越来越缺乏经验,可以在独立机器上运行的直观软件程序变得越来越重要。这种独立性带来了新的挑战:应用程序到应用程序的通信。我们用网络计算的进步来应对这一挑战,比如基于网络协议的远程过程调用:传输控制协议和互联网协议(TCP/IP)。
然而,出现了环境限制。用户在许多不同的操作系统、硬件平台和网络协议上部署应用程序。这种多样性进一步增加了应用程序间交互和数据共享的压力。
分布式计算成为不可避免的下一步。
分布式计算
在分布式计算软件体系结构模型中,独立开发的对象和组件构成由网络基础设施连接的应用程序。这种网络基础设施支持和管理功能之间的通信,而不管它们的网络位置如何。
不同的组件和对象可以驻留在不同的计算机上。这些组件只需要对应用程序透明,并像调用它们的应用程序一样进行交互。
客户机-服务器体系结构
客户机-服务器体系结构是分布式计算的先驱。在其两层设计中,上层管理应用程序的用户界面(UI)和业务逻辑(客户端),而下层管理组织和数据管理(服务器)。
UI 和业务逻辑必须与数据库服务器紧密耦合,以便顺利访问数据。像企业资源规划(ERP)软件这样的应用程序通常使用这种模型,其中客户端与中央数据库服务器的交互对于业务流程至关重要。
然而,客户机-服务器应用程序有其缺点。由于算法和逻辑在客户端,保护应用程序免受黑客攻击是一个巨大的挑战。客户的个性和频繁的呼叫使得系统维护成本高,资源密集(相对于今天),并且难以扩展,特别是对于复杂的业务流程,
值得注意的是,客户机-服务器系统仍然存在,尽管它们最适合于面向数据库的独立应用程序。开发人员通常应该避免使用这种架构来构建相当大的面向组件的应用程序。
面向服务的架构(SOA)
我们已经从传统的客户机-服务器体系结构走了很长一段路。随着. com 时代的到来,开发人员创建了面向服务的体系结构来升级传统的客户机-服务器体系结构。
在这种体系结构中,应用程序组件通过网络进行通信,相互提供服务。虽然 SOA 架构为我们带来了业务价值和可重用、松耦合服务的额外好处,但它们仍然依赖于规模有限的整体系统。
随着业务需求逐渐超过 SOA 价值,我们不可避免地要寻找更好的东西。
微服务架构
在微服务架构中,开发人员将应用构建为离散服务(模块)的集合,并通过高效的通信协议将它们绑定在一起。开发人员将应用程序分成独立的模块,处理业务流程的不同方面。
这些单独的模块可以使用不同的数据库,用不同的编程语言编写,存储在不同的计算机上,并且可以独立部署。
分布式系统最佳实践
尽管越来越多的应用程序正在采用分布式架构,但发现一个应用程序在设计时以微服务开始,但在部署时却以近乎整体的形式结束的情况并不少见。遵循这些最佳实践应该有助于避免这种结果。
最佳实践 1 -根据功能拆分服务
您必须做的第一件事是有效地组件化您的应用程序。
理想的组件是一个软件单元,您可以在不依赖于应用程序的其他单元的情况下开发和管理它。在微服务中,这意味着将您的应用程序分解成其组成服务。
构建分布式系统的目标是开发一个像编排一样执行的应用程序:即使每个部分都保持独立,它也必须与整体保持同步。我们希望能够隔离表现不佳的成员或修改序列,而不会无意中影响其他成员。
最佳实践 2 -明确定义服务界限
在软件世界里,就像在许多其他感兴趣的领域一样,你必须注意组成整体的部分。如何将应用程序分解成组件服务将影响流程同步和功能间的通信。
最佳实践 3 -确定分布式服务如何通信
在微服务中,组成服务的是进程外组件。它们通过 web 服务请求或远程过程调用进行通信。
您应该尽量减少服务之间的通信,但是,如果您的服务需要进行几次外部调用,例如像支付网关,这个限制是不可能的。
最佳实践 4 -选择交互式还是批处理
您的微服务需要相互通信以及与其他应用程序通信,因此要确定最佳的数据处理策略。
当最终用户与您的微服务交互时,您希望以最小的延迟提供快速响应。为了实现这一点,您需要评估微服务将如何以及何时管理和处理数据。您还需要确定组件应该存储哪些数据,以及它应该如何有效地管理这些数据,以确保这些数据可以随时访问。
您的应用程序可能需要实时(交互式)处理数据,或者按计划在后台执行(批处理)。例如,像优步这样的微服务应用程序必须适应高流量。因此,最好实时处理配置文件设置数据,并在后台了解您的客户(KYC)数据。
在哪里托管您的应用程序
彻底的软件架构从一个概念开始,并在那里成长。为什么要花时间去设计优秀的软件,却因为一个不那么优秀的虚拟机或操作系统而让它表现不佳?
考虑功能,而不是整个应用程序。对于持续集成(CI),您希望您的功能是完全可移动的和自动化友好的。你需要问自己:
- 哪些功能应该放在虚拟机中,哪些应该放在容器中?
- 哪个操作系统是实现这一功能的最佳环境:Windows、Linux、Unix 还是另一个?
- 函数应该使用哪种编程语言和数据库管理器,我们应该在云中还是在企业数据中心执行它?
- 我们的主机系统应该有什么系统架构:x64,x86,大型机,还是别的?
诸如此类。
不要局限于硬件解决方案。虚拟化让您可以用虚拟内存、虚拟机和虚拟桌面基础架构(VDI)等替代产品来替代服务器、内存和网络设备等传统硬件。
与硬件解决方案相比,这些解决方案更易于管理、部署更快,并且通常更具弹性。如果出现问题,它们不太可能出故障,也更容易修复。借助虚拟环境,您可以通过优化数据来降低成本和硬件需求。
这种划分是您可以获得分布式系统最重要的好处之一的地方:您可以为每个组件做最好的事情。
提示:根据每个组件的需求选择托管。
性能和维护
当您定义了流程流后,您下一步要考虑的应该是您期望该流程在标准条件下如何执行。是否存在会影响性能的资源或环境限制,如内存和处理能力?如果有,你应该意识到并在设计中明确这些限制。
确保性能和易于维护可能意味着审查您的组件,以进一步划分或合并一些组件。您希望设计能够在标准条件下发挥最佳性能。但是,您不希望它变得如此复杂,以至于危及安全性,并将维护变成一项艰巨的任务。
关键是保持开放的心态,这样你就不会偏向于你的设计或任何特定的解决方案。你的衡量标准应该是效率。如果有更好的方法,那就选择更好的。
提示:保持开放的心态,做好适应的准备。
可靠性
事实上,服务失败并不是 100%可以避免的。有些故障是由网络中断、系统资源不足或其他与代码无关的原因造成的。
你很难阻止这种类型的失败。有是你可以做的事情,以确定当故障出现时你的应用程序如何表现:你需要维护安全性和流畅的用户体验。
最佳实践是设计您的函数,使部分执行的更新完全回滚,以确保数据完整性。在服务失败的情况下,管理系统应该正确地记录报告。您还应该确定受影响的函数在失败后是否应该重新运行,以及它们是否应该重新输入数据。
安全性和隐私
正确保护您的分布式系统是您面临的最大挑战之一。采用设计安全方法是非常重要的。除了保护每个功能之外,您还必须保护通信通道,防止对敏感部件的未授权访问。
隐私也不能是事后的想法。仔细考虑您的目标用户所在地理区域的隐私政策和法规。
提示:从一开始就将安全性设计到您的架构中。
结论
设计一个分布式系统就像解决一个难题。如果你做得好(尤其是在 DevOps 中),它会带来长期的好处,但是你必须从设计阶段就把它做好。首先,花足够的时间来评估,然后根据需要重新设计或修改你的设计。
集中式系统仍然有效。从单片架构过渡到微服务架构并不像从模拟过渡到数字。
您的业务需求和应用程序的效用应该驱动您对软件架构模型的选择。然而,随着行业构建更复杂的系统,分布式系统变得更加重要。
为 Django 应用程序创建一个连续的部署管道
Django 是最流行的 web 开发框架,适用于 Python 编程语言。它的设计有助于快速开发,而不会影响专业应用程序的标准。它是免费的、开源的,使用模型-视图-模板架构模式,并封装了许多样板文件,使开发人员能够快速生产 web 应用程序。
在本教程中,您将学习并演示如何创建一个部署管道来将您的 Django 应用程序持续部署到一个托管环境中。
先决条件
要跟进这篇文章,需要做一些事情:
- Python 编程语言的基础知识
- 在你的系统上安装并更新了 Python (版本> = 3)
- 英雄的叙述
- 一个圆的账户
- GitHub 的一个账户
安装并设置好所有这些之后,您就可以开始本教程了。
克隆和运行示例 Django 项目
首先,您将克隆一个简单的 Django 项目,您可以用它来进行部署演示。要克隆项目,请运行:
git clone --single-branch --branch base-project https://github.com/CIRCLECI-GWP/cci-cd-django
克隆完成后,进入项目根目录(cd cd-django-site
)并运行以下命令,使用本地 Python 服务器启动项目:
python manage.py runserver
这将启动服务器并在地址http://localhost:8000
运行应用程序。将此地址加载到您的浏览器中。
创建 Heroku 应用程序
下一步是设置一个 Heroku 应用程序来托管这个应用程序。进入你的 Heroku 仪表盘,点击新建 - > 新建 app 。输入新应用程序的名称。
记下您刚刚输入的姓名。在本教程的后面部分,您将需要用到它。接下来,在仪表板的 Account Settings
部分找到您的 Heroku API 密钥。在教程的后面部分,您也将需要它。
为部署设置 CircleCI 项目
要开始这个过程,首先需要将项目推送到 GitHub 上的一个远程存储库。确保这是连接到您的 CircleCI 帐户的 GitHub 帐户。
接下来,转到 CircleCI 仪表板上的项目页面(点击右侧垂直菜单上的项目)。添加项目。
点击设置项目开始。在弹出的模式上点击跳过这一步。我们将在本教程的后面手动添加 CircleCI 配置。
在设置页面上,点击 Use Existing Config 表示您正在手动添加一个配置文件,并且不使用显示的示例。接下来,您会得到提示,要么下载管道的配置文件,要么开始构建。
点击开始建造。这个构建将会失败,因为我们还没有设置配置文件。
我们需要在 CircleCI 控制台上做的最后一件事是为我们刚刚添加的项目设置环境变量。这将使我们的项目能够对我们的 Heroku 应用程序进行身份验证访问以进行部署。
点击 Pipelines 页面上的项目设置按钮,转到您的项目设置。确保您的项目是被选中的项目。
回到项目设置页面,点击侧面菜单上的环境变量。
在环境变量页面上,点击添加环境变量。
添加以下环境变量:
HEROKU_APP_NAME
是您的 Heroku 应用程序的名称(在本例中,名称是cci-cd-django
)。HEROKU_API_KEY
是您的 Heroku 帐户 API 密钥。可以从 Heroku 的账号页面复制粘贴。
现在您已经添加了环境变量,您已经在 CircleCI 控制台上为部署到 Heroku 做好了一切准备。
Django 应用程序的自动化部署
为了完成这个过程,您需要设置 Django 项目,以便在 Heroku 上进行部署。
首先为 Python 安装 Gunicorn web 服务器。Gunicorn 是 Heroku 在生产中运行 Django 应用程序的首选服务器。在项目的根目录下,通过运行以下命令安装 Gunicorn:
pip install gunicorn
接下来,安装psycopg2
,这是 Python 应用程序的 Postgres 适配器。输入以下命令:
pip install psycopg2-binary
为了成功部署,Heroku 还需要安装和配置django-heroku
包。通过运行以下命令安装此软件包:
pip install django-heroku
安装完成后,在my_django_project/settings.py
文件的顶部导入这个最新的包。将其放在线from pathlib import Path
的正下方。
import django_heroku
然后在文件的底部,添加下面一行:
django_heroku.settings(locals())
安装完所有依赖项后,更新跟踪所有依赖项的requirements.txt
文件。输入以下命令:
pip freeze > requirements.txt
在上面的命令中,pip freeze
用于将所有依赖项放入项目中,并将该命令的输出发送到requirements.txt
文件中。这一步是 Heroku 要求的。
接下来,在项目的根目录下创建一个名为 Procfile
的文件(Heroku apps 包含一个 Procfile,它指定了应用程序在启动时执行的命令),并添加以下行:
web: gunicorn my_django_project.wsgi
该命令指示 Heroku 使用gunicorn
服务器运行应用程序。现在,确保 Django 应用程序成功部署到 Heroku 已经万事俱备了。
现在您可以编写连续部署管道脚本,将项目从您的本地环境运送到 Heroku 的远程托管环境。
在项目的根目录下,创建一个名为.circleci
的文件夹,其中包含一个名为config.yml
的文件。在config.yml
中,输入此代码:
version: 2.1
orbs:
heroku: circleci/heroku@0.0.10
workflows:
heroku_deploy:
jobs:
- heroku/deploy-via-git
在这个配置中,Heroku orb circleci/heroku@0.0.10
被导入,它自动提供对一组 Heroku 作业和命令的访问,使 Heroku toolbelt 易于使用。其中一个任务是heroku/deploy-via-git
,它将应用程序直接从 GitHub repo 部署到 Heroku 帐户。这项工作已经负责安装 Heroku CLI、安装项目依赖项和部署应用程序。它还会获取您的环境变量,以便顺利部署到 Heroku。
提交对项目的所有更改,并推送到您的远程 GitHub 存储库。这将自动触发部署管道。
成功!接下来,单击 build(heroku/deploy-via-git),获取关于部署的详细信息。
获得成功的构建是很好的,但是你需要确认你的应用在 Heroku 上实际上没有错误。为此,请访问您的 Heroku 分配的应用程序 URL。URL 的格式应该是https://[APP_NAME].herokuapp.com
。对于本教程,URL 是:https://cci-cd-django.herokuapp.com/
。
太棒了。
结论
Python 开发人员喜欢使用 Django,因为它具有丰富的特性和易于使用的 API。Python 本身是一种开发人员友好的语言,Django 使得将 Python 用于 web 应用程序成为一个很好的选择。如果你的团队使用这些工具,让他们知道你在本教程中学到了什么。使用连续部署管道来自动部署您的 Django 应用程序的好处只有在其他团队成员能够访问信息时才会增加。让你的团队少一件担心的事。
编码快乐!
Fikayo Adepoju 是 LinkedIn Learning(Lynda.com)的作者、全栈开发人员、技术作者和技术内容创建者,精通 Web 和移动技术以及 DevOps,拥有 10 多年开发可扩展分布式应用程序的经验。他为 CircleCI、Twilio、Auth0 和 New Stack 博客撰写了 40 多篇文章,并且在他的个人媒体页面上,他喜欢与尽可能多的从中受益的开发人员分享他的知识。你也可以在 Udemy 上查看他的视频课程。
Docker 和 CI/CD 教程:深入了解容器
原文:https://circleci.com/blog/docker-and-cicd-tutorial-a-deep-dive-into-containers/
这是我在 CircleCI 2.0 发布后写的上一篇的后续。这个版本使用 Docker 执行器实现了构建支持。发布后,我们意识到 CircleCI 用户遇到的最大障碍之一是缺乏使用 Docker 的经验。这一点通过我在社区和活动中与众多开发者的对话得到了证实,他们在持续集成管道中使用了容器技术。这些对话强调了许多开发人员并没有完全理解如何使用容器技术。
在这篇文章中,我将扩展并演示我在上一篇文章中讨论的一些更有用的 Docker 命令。
Docker 是什么?
以下是我在上一篇文章中使用的 Docker 的简化定义:
Docker 是开发人员和系统管理员使用容器开发、部署和运行应用程序的平台。
Docker 也被称为应用程序打包工具,它使应用程序能够被配置并打包到一个 Docker 映像中,该映像可用于生成运行应用程序实例的 Docker 容器。它提供了许多好处,包括运行时环境隔离、代码一致性和可移植性。Docker 容器可以在任何支持 Docker 引擎的操作系统上运行。
基本码头术语
这里有一个基本 Docker 命令和术语的列表,带有更多信息的链接。这些有助于你了解 Docker,控制执行人。这些命令可以在任何安装了 Docker 引擎的计算机上本地运行。
构建 Docker 图像
Dockerfile
一个文本文档,包含用户可以在命令行上调用的所有命令来组合一个图像。
Docker 文件是构建 Docker 映像的蓝图。Docker 文件模板包含一些元素,例如用作基础的基本操作系统映像、安装/配置依赖项的执行命令以及将本地源代码或工件推入目标 Docker 映像的复制命令。下面是一个简单 Node.js 应用程序的 docker 文件示例:
FROM node:10
# Create app directory
WORKDIR /usr/src/app
# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm@5+)
COPY package*.json ./
RUN npm install --only=production
# If you are building your code for production
# RUN npm install --only=production
# Bundle app source
COPY . .
EXPOSE 5000
CMD [ "npm", "start" ]
该命令用于列出本地机器上当前存在的所有 Docker 映像和相关数据。它类似于 linux ls
或 windows dir
命令,用于显示终端中目录的内容。该命令对于理解如何在本地管理、维护和构建 Docker 映像非常有用。下面是一个docker images
执行的结果示例:
REPOSITORY TAG IMAGE ID CREATED SIZE
ariv3ra/nodejs-circleci latest f419e4a6b1b8 11 days ago 943MB
node 10 01b816051d34 2 weeks ago 911MB
circleci/python 3.7.6 0d2975896c73 5 weeks ago 1.43GB
ariv3ra/infrastructure-as-code101 latest cb21a36a2973 8 weeks ago 929MB
python 3.7.6 879165535a54 2 months ago 919MB
circleci/rust 1-buster 218329b929cf 2 months ago 1.68GB
rust 1-buster f5fde092a1cd 2 months ago 1.19GB
python 3.7.4 9fa56d0addae 6 months ago 918MB
Docker 命名约定上面的命令,结合一个有效的Dockerfile
,基于Dockerfile
中定义的执行命令构建一个 Docker 镜像。构建映像和启动容器的一个关键要素是理解 Docker 命名约定。使用该命令构建 Docker 映像指定了目标 Docker 映像的名称。Docker images 使用由斜杠分隔的名称组成的命名约定,其中可能包含小写字母、数字和分隔符。分隔符定义为句点、一个或两个下划线、一个或多个破折号。名称组件不能以分隔符开头或结尾。一个 docker 标签名称必须是有效的 ASCII,并且可以包含小写和大写字母、数字、下划线、句点和破折号。标记名不能以句点或破折号开头,最多可以包含 128 个字符。您可以使用名称和标签将图像分组。在本帖中,我们将使用这个命名约定。
既然我们已经讨论了命名约定,让我们基于上面例子中的Dockerfile
构建一个 Docker 映像。在本帖中,我们可以利用punk data/nodejs-circle cigit repo。在本地克隆它并将$ cd
放入项目目录。
然后运行这个命令,根据项目源代码和示例Dockerfile
构建一个新的 Docker 映像:
docker build -t tutorial/circleci-node:10 .
运行此构建命令后,您将看到类似如下的结果:
Sending build context to Docker daemon 98.07MB
Step 1/7 : FROM node:10
---> 01b816051d34
Step 2/7 : WORKDIR /usr/src/app
---> Using cache
---> 12b2edc2b97c
Step 3/7 : COPY package*.json ./
---> Using cache
---> 53b5b8e4e654
Step 4/7 : RUN npm install --only=production
---> Using cache
---> eefdf560bc4d
Step 5/7 : COPY . .
---> aa7d54e955c6
Step 6/7 : EXPOSE 5000
---> Running in cc427dbafdcc
Removing intermediate container cc427dbafdcc
---> 4ce9084e39eb
Step 7/7 : CMD [ "npm", "start" ]
---> Running in f6e854599ddc
Removing intermediate container f6e854599ddc
---> 79a8d94cbf42
Successfully built 79a8d94cbf42
Successfully tagged tutorial/circleci-node:10
运行docker images
命令,您将会在结果中看到您新创建的 Docker 映像。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tutorial/circleci-node 10 79a8d94cbf42 4 minutes ago 1.03GB
现在,您已经构建了一个非常棒的 Docker 映像,并可以使用了。在下一节中,我将以 Docker containers
的形式创建这个 Docker 图像的新实例
Docker 容器
- Docker 容器旨在隔离和大规模运行应用程序。它们允许简化应用程序的管理和实现。
在我们开始创建和运行 Docker 容器之前,我将添加一些上下文。Docker 容器是基于并衍生自 Docker 图像的对象。Docker 图像是模板。我把它们比作饼干模具。饼干模具使您能够快速、一致地从面团中制作出单个的饼干。我把这些饼干比作 Docker 容器,它们在形状上通过切割/建造过程中使用的饼干模具或 Docker 容器的类型来区分。因此,使用我的 cookie cutter 类比,Docker 图像是 cookie cutter,使用该 cutter 切割的单个 cookie 相当于 Docker 容器。
现在我可能已经为你做了一点匈牙利饼干,让我们开始运行一些容器。
这个命令是 Docker 运行时最重要的命令,负责创建和启动 Docker 容器。
让我们开始一个名为nodetest01
的新容器:
docker run -d -p 5000:5000 --name nodetest01 tutorial/circleci-node:10
恭喜你。现在,您应该让 Node.js 映像在刚刚创建的新容器中运行,该容器在端口 5000 上可用。打开网络浏览器并转到此地址:http://localhost:5000
。它将静态显示“欢迎使用 CircleCI 学习 CI/CD 101!”此应用程序提供的网页。您还可以通过在终端中执行一个docker ps
命令来验证您的容器正在运行。我们将在下一节讨论这一点。在此之前,让我们通过运行另一个容器来启动应用程序的另一个实例。
我们用名称nodetest01
开始了我们的第一个容器,由于容器名称必须是惟一的,我们将把我们的新容器命名为nodetest02
。我们的新容器中必须进行的另一个更改是端口号。我们将把它从5000
改为5001
,因为应用程序不能在同一个网络接口上占用同一个端口号。
在终端中执行以下docker run
命令:
docker run -d -p 5001:5000 --name nodetest02 tutorial/circleci-node:10
厉害!现在,您在本地机器上运行了两个容器。你可以在浏览器中访问这个地址http://localhost:5001
,并在你的第二个 Docker 容器中查看应用程序的运行情况。
docker run
命令非常健壮,有许多属性和配置标志,我在这篇文章中无法解决或演示。我强烈建议您阅读并熟悉可以执行和运行 Docker 容器的许多方法。你可以在这里阅读 Docker 容器命令。
docker ps
列出了所有正在运行的 Docker 容器。该命令的作用与docker image
命令相似,列出了正在运行的容器。使用-a
标志显示所有正在运行和没有运行的容器。
在终端中运行这个命令,您应该能够在结果中看到前面创建的两个容器正在运行:
docker ps
结果将与此类似,显示node01
和node02
容器仍在运行。
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
dfd30181e15c tutorial/circleci-node:10 "docker-entrypoint.s…" 12 minutes ago Up 12 minutes 0.0.0.0:5001->5000/tcp nodetest02
0efaf7f11780 tutorial/circleci-node:10 "docker-entrypoint.s…" 28 minutes ago Up 28 minutes 0.0.0.0:5000->5000/tcp nodetest01
该命令仅用于启动通过docker run
命令创建的现有容器。除非用docker run
命令指定了--rm=true
标志,否则新创建的容器将持续存在,并可以用docker start
和docker stop
命令重用。
让我们通过执行以下命令来停止一些正在运行的容器:
docker stop nodetest01 nodetest02
这些正在运行的容器现在应该处于非活动状态并已停止。由于它们已经停止,运行docker ps -a
命令,您将会看到类似下面的结果,指示停止的容器。
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
dfd30181e15c tutorial/circleci-node:10 "docker-entrypoint.s…" 31 minutes ago Exited (0) 38 seconds ago nodetest02
0efaf7f11780 tutorial/circleci-node:10 "docker-entrypoint.s…" About an hour ago Exited (0) 38 seconds ago nodetest01
尽管这些容器被停止,但它们将持续存在,并且可以使用docker start
命令重新启动。
让我们启动nodetest01
容器,这样我们可以在下一节学习如何使用docker logs
特性。
docker start nodetest01
现在运行docker ps -a
命令。注意这个容器的状态类似于Up about a 30 seconds
或者类似的意思。
该命令使开发人员能够查看执行时出现的日志。因为您的应用程序是在这些容器中运行的,所以 logs 命令对于读取关键的应用程序输出非常有用。这有助于了解应用程序的运行情况以及可能需要的任何调试/故障排除。
让我们对nodetest01
容器运行docker logs
命令:
docker logs nodetest01
运行该命令后,您应该会看到如下所示的结果。这表明容器内的应用程序已经启动并运行。
Node server is running..
> nodejs-circleci@0.0.1 start /usr/src/app
> node app.js
Node server is running..
持久化 Docker 容器会消耗其主机上的磁盘空间和资源。从操作上来说,将每个容器都保存在磁盘上没有多大意义,因为在大多数情况下,容器都是一次性的,应该这样使用。因此,当不再需要容器时,应该将其从宿主中永久丢弃。docker rm
命令从主机上永久删除容器。不再需要nodetest02
容器,所以让我们节省一些磁盘空间并删除它。注意此命令将只删除非活动/停止的容器,如果对活动/运行的容器运行,将会出错。
对nodetest02
容器运行docker rm
命令:
docker rm nodetest02
运行docker ps -a
之后,您应该在主机上不再看到nodetest02
容器。这个命令有其他的属性和标志,你应该在这里熟悉它们。
此命令适用于从主机中删除 Docker 映像。如果主机上存在基于特定映像的现有容器,则此命令不允许删除基于映像的容器。在使用此docker rmi
命令删除 Docker 图像之前,您必须首先确保停止并删除容器。在这里阅读 docker rmi 命令
Docker 映像部署
许多 Docker 图像是公开可用的,并托管在 Docker Hub Registry 上,这是 Docker 图像的在线中央托管解决方案。Docker Hub 使任何有互联网连接的人都可以将公开的图片从注册表下载到他们的本地机器或服务器上。它还允许注册用户上传并公开分享他们的任何容器,这样任何人都可以从 Docker Hub 下载图片。
在接下来的部分中,我将简要讨论一些与 Docker Hub 相关的命令。
docker pull
从注册表中取出一个映像或存储库。
此命令使您能够从 Docker Hub 下载有效的 Docker 映像。公开可用的 Docker 图像不需要认证。如果注册中心是私有的,你需要使用一个指定的证书进行认证,通常是用户名和密码。
该命令使您能够根据 Docker 注册表进行身份验证。如果你使用这个登录命令,你应该用你的 Docker Hub 账户用户名和密码填充一个. txt 文件,以保护这些凭证不被暴露。
docker push
将图像或存储库推送到注册表。
此命令使用户能够将图像上传到 Docker 注册表,并且需要有效的凭据。
摘要
所以你有它。在这篇文章中,我深入解释了 Docker 术语和命令以及容器和它们的用法。我讨论和演示的命令是 Docker 运行时中最广泛使用的命令,了解更多关于它们及其属性和标志的知识肯定会帮助您提高 Docker 和容器技能。
熟悉这些基本命令将会消除 CircleCI 新用户遇到的一个更大的障碍。
如果你想了解更多关于 CircleCI 的信息,请查看文档网站,如果你真的遇到困难,你可以通过 https://discuss.circleci.com/社区/论坛网站联系 CircleCI 社区。
Docker 图像与容器:有什么区别?圆环
如果你是 Docker 的新手,你可能会发现理解所有的术语很有挑战性。似乎每个人对 Docker 术语的含义都有不同的理解,有时术语会互换使用。
例如,像其他正在学习 Docker 的人一样,您可能想知道 Docker 图像与 Docker 容器有何不同。他们的对比微妙但意义重大。
本文将探讨 Docker 图像和容器之间的差异,帮助您理解如何以及何时使用它们。
Docker 概述
像 Docker、Flatpak 和 Snaps 这样的解决方案都有一个相同的目标,就是将一个应用程序打包成一个包,安装在任何 Linux 发行版中。
Solomon Hykes 在 2013 年引入 Docker 作为开源项目。他们的第一个商业版本将于 2014 年投入生产。
Docker 容器化平台有助于通过使用容器轻松创建、部署和运行应用程序。可以把容器想象成软件的运输容器——它保存重要的内容,如文件和程序,这样应用程序就可以有效地从生产者交付给消费者。
容器化最大的好处之一是,它使开发者能够将他们的应用程序与在任何 Linux 发行版上运行所需的所有依赖项打包在一起。这消除了手动安装每个依赖项的需要。
多个容器可以同时运行,每个基于相同或不同的图像。Docker 在创建操作系统的多个实例的方式上类似于虚拟机。然而,Docker 允许您创建在相同的操作系统上运行的容器。因此,在给定的硬件组合上,可以运行比虚拟机更多的容器。
Docker 容器甚至可以在虚拟机中运行。与创建虚拟机相比,Docker 提供了一个额外的抽象和自动化层,使其更易于使用。
容器化平台越来越受开发人员和系统管理员的欢迎,因为它包含了应用程序的完整文件系统及其所有依赖项。这种设置支持不可变的基础设施,并保证部署是幂等的——无论您重复操作多少次,它们都将保持完全相同。
Docker 守护进程在后台运行,管理图像、容器等。客户端和守护进程使用套接字或通过 RESTful API 进行通信。
什么是 Docker 图像?
图像是只读模板,包含创建容器的说明。Docker 映像创建在 Docker 平台上运行的容器。
可以把一个图像想象成一个运行时容器中内容的蓝图或快照。
图像由多个堆叠的层组成,就像照片编辑器中的层一样,每个层都会改变环境中的一些内容。映像包含运行应用程序的代码或二进制文件、运行时、依赖项和其他文件系统对象。该映像依赖于主机操作系统(OS)内核。
例如,要构建一个 web 服务器映像,从包含 Ubuntu Linux(一个基本操作系统)的映像开始。然后,在上面添加 Apache 和 PHP 之类的包。
您可以使用 Docker 文件手动构建映像,Docker 文件是一个包含创建 Docker 映像的所有命令的文本文档。您还可以使用命令docker pull [name]
从名为 registry 的中央存储库中,或者从 Docker Hub 这样的存储库中提取图像。
当 Docker 用户运行一个图像时,它会变成一个或多个容器实例。容器的初始状态可以是开发人员想要的任何状态——它可能已经安装并配置了 web 服务器,或者除了作为根用户运行的 bash shell 之外什么也没有。然而实际上,大多数映像都包含一些预配置的软件和配置文件。
Docker 映像是不可变的,因此一旦创建就不能更改。如果需要更改某些内容,请使用所做的更改创建另一个容器,然后将这些更改保存为另一个图像。或者,只需使用现有图像作为基础运行新容器,然后更改该图像。
成功构建应用程序后,Docker 可以进一步将图像导出到其他图像中。彼此派生的映像通常称为父映像和子映像。
一个图像可能有多个标签,但每个标签都是唯一的。标签区分图像,例如 ubuntu:latest 或 ubuntu:14.04。
图像本身不会运行,但是您可以从 Docker 图像创建和运行容器。
什么是容器?
容器是一个隔离的地方,应用程序在其中运行,不会影响系统的其余部分,系统也不会影响应用程序。因为它们是隔离的,所以容器非常适合于安全地运行需要访问敏感资源的软件,如数据库或 web 应用程序,而无需向系统上的每个用户授予访问权限。
由于容器在 Linux 上本地运行并共享主机的内核,所以它是轻量级的,不会比其他可执行文件占用更多的内存。如果您停止一个容器,它不会自动重新启动,除非您这样配置它。然而,容器比虚拟机更有效,因为它们不需要整个操作系统的开销。它们与其他容器共享一个内核,并在几秒钟而不是几分钟内启动。
您可以使用容器来打包应用程序及其所需的所有组件,然后将它们作为一个单元发送出去。这种方法很受欢迎,因为它消除了开发、QA 和生产环境之间的摩擦,实现了更快的软件交付。在软件容器中构建和部署应用程序消除了与其他开发人员协作编写代码时“在我的机器上工作”的问题。
这些应用还可以在任何基础设施和云中运行。您可以将应用程序及其底层基础结构与其他应用程序隔离开来。
Docker 图像与容器
Docker 映像执行 Docker 容器中的代码。您可以在 Docker 映像上添加一个核心功能的可写层来创建一个运行容器。
把 Docker 容器想象成一个运行的图像实例。您可以从同一个映像创建许多容器,每个容器都有自己唯一的数据和状态。
虽然图像不是创建容器的唯一方法,但它是一种常见的方法。
采用容器的一个主要好处是开发、操作和测试的标准化和简化。然而,为了让团队充分利用容器,他们需要确保开发人员、操作工程师和测试人员创建一致的环境。
一个持续集成和持续部署(CI/CD)管道可以构建、测试和打包容器。然后,部署将该容器分发到运行时环境,在那里它可以作为应用程序的一部分执行。
像 CircleCI 这样的持续集成解决方案使开发人员能够自动化构建、测试和部署。CircleCI 可以使用 Docker 容器来更容易地将应用程序部署到多个环境中。
例如,CircleCI 可以构建 Docker 映像,并将它们推送到 Docker Hub 这样的容器映像注册中心。从那里,它可以将图像实例化到 Kubernetes、OpenShift 或其他地方的容器中。
流程是这样的:
- 您提交对 Git repo 的更改。
- 这个提交触发了一个 CircleCI 构建作业,该作业从 Git 中签出源代码,并对代码运行单元测试。
- 如果单元测试通过,CircleCI 会将构建的映像推送到 Docker Hub。
- 如果单元测试失败,CircleCI 会提醒开发人员并停止工作流。
像 Docker 层缓存和测试分割这样的功能也可以帮助您更快地构建和测试您的映像,缩短您的部署时间。有关使用持续集成平台来协调 Docker 构建、测试和部署的更多好处,请访问如何使用 Docker 构建 CI/CD 管道。
结论
虽然 Docker 图像和容器有相似的目的,但是它们有不同的用途。映像是环境的快照,容器运行软件。
容器和映像都允许用户指定应用程序依赖性和配置,并描述机器运行该应用程序所需的一切。然而,容器和图像具有不同的生命周期。例如,您可以在基于容器的系统(如 Pivotal Cloud Foundry)上使用容器,但不能使用映像。同样,在 Heroku 或 OpenShift 这样的非容器系统中,您可以使用图像,但不能使用容器。
这不是选择容器或图像的问题。它们相互依赖,你需要两者与 Docker 一起工作。
现在您已经理解了 Docker 图像和容器之间的细微差别,您可以充分利用 Docker 平台了。使用 Docker 时,自动化有助于您快速集成,并释放开发人员的时间来创建新的应用程序功能。了解更多关于 CircleCI 的 Docker 和 Kubernetes 集成如何提高软件开发过程的效率。
Docker Swarm vs Kubernetes:如何选择容器编排工具
世界各地的企业越来越依赖容器技术的好处来减轻部署和管理复杂应用程序的负担。容器将所有必需的依赖项组合在一个包中。它们可移植、快速、安全、可扩展且易于管理,是传统虚拟机的首选。但是要扩展容器,你需要一个容器编排工具——一个管理多个容器的框架。
今天,最著名的容器编排平台是 Docker Swarm 和 T2 Kubernetes。它们都有优点和缺点,并且都有特定的用途。在本文中,我们将研究这两种工具,以帮助您确定哪种容器编排工具最适合您的组织。
码头工人群
Docker Swarm 是一个由 Docker 构建和维护的开源容器编排平台。在幕后,Docker Swarm 将多个 Docker 实例转换成一个虚拟主机。Docker Swarm 集群通常包含三个项目:
- 节点
- 服务和任务
- 负载平衡器
节点是 Docker 引擎的单个实例,它控制您的集群并管理用于运行服务和任务的容器。Docker Swarm 集群还包括负载平衡,以便在节点间路由请求。
Docker Swarm 的优势
Docker Swam 安装起来很简单,尤其是对于那些刚刚进入容器编排领域的人来说。它重量轻,易于使用。此外,Docker Swarm 比更复杂的编排工具更容易理解。它在 Docker 容器中提供自动负载平衡,而其他容器编排工具需要手动操作。
Docker Swarm 与 Docker CLI 配合使用,因此无需运行或安装整个新的 CLI。此外,它可以与现有的 Docker 工具(如 Docker Compose)无缝协作。
如果你的系统已经在 Docker 中运行,Docker Swarm 不需要改变配置。
Docker Swarm 的缺点
尽管有好处,使用 Docker Swarm 也有一些你应该知道的缺点。
首先,与 Kubernetes 相比,它是轻量级的,并且绑定到 Docker API,这限制了 Docker Swarm 中的功能。同样,Docker Swarm 的自动化功能也不像 Kubernetes 那样强大。
库伯内特斯
Kubernetes 是一个开源的容器编排平台,最初由 Google 设计来管理他们的容器。Kubernetes 拥有比 Docker Swarm 更复杂的集群结构。它通常有一个构建器和工作节点架构,进一步分为 pod、名称空间、配置映射等等。
Kubernetes 的优势
Kubernetes 为寻找健壮的容器编排工具的团队提供了广泛的好处:
- 它有一个庞大的开源社区,谷歌也支持它。
- 它支持所有的操作系统。
- 它可以支持和管理大型架构和复杂的工作负载。
- 它是自动化的,并且具有支持自动扩展的自我修复能力。
- 它具有内置的监控和广泛的可用集成。
- 它由三个主要的云提供商提供:Google、Azure 和 AWS。
由于其广泛的社区支持和处理最复杂部署场景的能力,Kubernetes 通常是管理基于微服务的应用程序的企业开发团队的首选。
Kubernetes 的缺点
尽管 Kubernetes 功能全面,但它也有一些缺点:
- 它有一个复杂的安装过程和陡峭的学习曲线。
- 它要求您安装单独的 CLI 工具并学习每一个工具。
- 从 Docker Swarm 到 Kubernetes 的过渡可能很复杂,也很难管理。
在某些情况下,Kubernetes 可能过于复杂,导致生产力的损失。
Docker Swarm vs Kubernetes:异同
到目前为止,我们已经讨论了每个平台的优点和缺点。现在,让我们来分析它们的主要区别和相似之处。我们将从设置要求、应用部署能力、可用性和可扩展性、监控功能、安全性和负载平衡等方面对这两个平台进行比较。
安装、配置和学习曲线
与 Kubernetes 相比,Docker Swarm 易于安装,并且实例通常在整个操作系统中保持一致。在 Docker Swarm 中配置集群比配置 Kubernetes 更容易。与它的对应物相比,它很容易学习,并且可以与现有的 CLI 一起工作。
与 Docker Swarm 相比,Kubernetes 的安装更复杂,需要手动操作。每个操作系统的安装说明可能会有所不同。学习起来很有挑战性,而且有单独的 CLI 工具。
应用程序部署
Docker Swarm 应用程序是您可以使用 YAML 文件或 Docker Compose 部署的服务或微服务。
Kubernetes 提供了更广泛的选项,比如名称空间、pod 和部署的组合。
可用性和可扩展性
Docker Swarm 提供高可用性,因为您可以轻松复制 Docker Swarm 中的微服务。而且 Docker Swarm 部署时间更快。另一方面,它不提供自动缩放。
Kubernetes 天生具有高可用性、容错性和自我修复能力。它还提供自动缩放功能,并可以在需要时更换有故障的 pod。
监视
Docker Swarm 只支持通过第三方应用进行监控。没有内置的监测机制。
相比之下,Kubernetes 具有内置的监控功能,并支持与第三方监控工具的集成。
安全性
Docker Swarm 依靠传输层安全(TLS)来执行安全和访问控制相关的任务。
Kubernetes 支持多种安全协议,如 RBAC、SSL/TLS、秘密管理、策略等等。
负载平衡
Docker Swarm 支持自动负载平衡,并在幕后使用 DNS。
Kubernetes 没有自动负载平衡机制。但是,Nginx Ingress 可以充当集群中每个服务的负载平衡器。
K3s 作为替代产品
总之,两个平台的主要区别是 Docker Swarm 是轻量级的,更适合初学者,而 Kubernetes 是笨重而复杂的。寻找中间地带的开发者可能会考虑一个新的平台, K3s 。K3s 消除了 Kubernetes 的复杂性,并提供了一种更轻松、更容易获得的体验。
K3s 是一个微小的二进制文件,实现了完整的 Kubernetes API。它很小,因为二进制文件没有不必要的包。您可以使用第三方加载项快速添加功能。它是轻量级的,易于使用,并且通过了云本地计算基金会(CNCF)的认证。
K3s 对 Docker Swarm 用户更友好,他们不确定自己是否准备好了全面使用 Kubernetes。它可能是笨重的 Kubernetes 的理想替代品。
你应该使用哪个平台?
Kubernetes 和 Docker Swarm 都服务于特定的用例。哪一种最适合您取决于您组织的需求。
对于初学者来说,Docker Swarm 是一个易于使用的简单解决方案,可以大规模管理您的容器。如果您的公司正在转向容器领域,并且没有复杂的工作负载需要管理,那么 Docker Swarm 是正确的选择。
如果您的应用程序很复杂,并且您正在寻找一个完整的包,包括监控、安全特性、自我修复、高可用性和绝对的灵活性,那么 Kubernetes 是正确的选择。
如果你需要 Kubernetes 的所有功能,但是被它的学习曲线所阻碍,那么 K3s 是一个不错的选择。
结论
在本文中,我们探讨了容器世界的两个主要协调者,Kubernetes 和 Docker Swarm。与 Kubernetes 相比,Docker Swarm 是一个轻量级、易于使用的编排工具,提供的服务有限。相比之下,Kubernetes 虽然复杂但功能强大,并且提供开箱即用的自我修复、自动伸缩功能。K3s 是 CNCF 认证的 Kubernetes 的一个轻量级版本,如果你想获得 Kubernetes 的好处而又不需要额外的学习开销,它可能是一个正确的选择。
哪种编排工具最适合您取决于您的业务需求。在做出选择之前,仔细考虑你的团队的目标和经验。无论您选择哪种平台,您都能够很好地扩展和管理您的容器化应用程序。
关于 Docker 和 CircleCI 你需要知道的
CircleCI 2.0 使用 Docker 执行器实现了构建支持。在发布时,我们很快意识到 CircleCI 用户遇到的最大障碍之一是缺乏使用 Docker 的经验。在本帖中,我们将讨论 Docker 和一些用户应该熟悉的基本命令。
Docker 是什么?
" Docker 是开发者和系统管理员使用容器开发、部署和运行应用程序的平台."
Docker 也被称为应用程序打包工具,它使应用程序能够被配置并打包到一个 Docker 映像中,该映像可用于生成运行应用程序实例的 Docker 容器。它提供了许多好处,包括运行时环境隔离、代码一致性和可移植性。Docker 容器可以在任何支持 Docker 引擎的操作系统上运行。对我们有利的是,大多数操作系统都支持它。
码头工人执行人
CircleCI 平台使用了一个叫做执行器的概念。执行器是您的 CI/CD 作业/配置在 CircleCI 平台中运行的环境。CircleCI 目前支持三种不同的执行器类型:
在这篇博文中,我们将讨论 Docker executor。
配置 Docker 执行器
CircleCI 作业定义在一个 config.yml
构建配置文件中。您可以在这里为您的构建指定 Docker 执行器的用法。下面是一个config.yml
文件的摘录,显示了一个执行者的定义:
version: 2
jobs:
build:
docker:
- image: circleci/python:2.7.14
docker:
键指示平台在 Docker 执行器上构建,而- image:
键指定在生成 Docker 容器时使用哪个 Docker 映像。构建将在基于circleci/python:2.7.14
映像的 Docker 容器中执行。
基本 Docker 命令
为了回应用户缺乏经验的问题,我们编辑了一个基本 Docker 命令和更多信息链接的列表。这些有助于你了解 Docker,控制执行人。这些命令可以在任何安装了 Docker 引擎的计算机上本地运行。
构建 Docker 图像
Docker 容器
Docker 映像部署
此外,理解 Dockerfile: 的概念也很重要,Dockerfile 是一个文本文档,它包含用户可以在命令行上调用的所有命令来组合一个图像。
上面列出的命令是用户通过 Docker 引擎可以使用的所有 Docker 命令的一个子集。它们代表了一组相关的命令,可以让用户快速熟悉 Docker。你可以在这里了解更多关于 Docker 命令的信息。
在 CircleCI 上构建 Docker 图像
CircleCI 有一个非常酷的特性,使用户能够轻松地在其 CI/CD 管道中构建 Docker 映像。setup_remote_docker:
键是一个特性,可以在 Docker executor 作业中构建、运行和推送映像到 Docker 注册表。当docker_layer_caching
设置为true
时,CircleCI 将尝试重新使用在之前的工作或工作流程中构建的任何 Docker 图像(层),这些图像保持不变。也就是说,在之前的作业中构建的每个未更改的图层都可以在远程环境中访问。然而,有些情况下,即使配置指定了docker_layer_caching: true
,您的作业也将在干净的环境中运行。这些情况涉及到为依赖于相同环境的相同项目运行许多并行作业。有关 Docker 层缓存的更多信息,请查看文档页面。
摘要
在这篇文章中,我们讨论了 CircleCI Docker 执行器和一些“必须知道”的 Docker 命令。熟悉这些基本命令将会消除 CircleCI 新用户遇到的一个更大的障碍。
如果你想了解更多关于 CircleCI 的信息,请查看文档网站,如果你真的遇到了困难,你也可以通过 https://discuss.circleci.com/社区/论坛网站联系 CircleCI 社区。
用 CircleCI 和 Jib 对接 Java 应用程序
原文:https://circleci.com/blog/dockerizing-java-apps-with-circleci-and-jib/
本文是全球 DNS 背后的多云部署系列文章的第一篇。
部署平台和编排引擎的发展已经成为应用程序和基础设施团队的巨大催化剂。我们的技术堆栈各层之间清晰的边界和定义良好的接口意味着我们可以快速迭代和部署,并获得可重复的结果。对于许多团队来说,Docker 已经成为这个架构中的一个关键要素,允许部署到像 Kubernetes 这样的平台上。
在 Docker 中包装应用程序是加强正确的依赖关系和操作系统的强大方法。不幸的是,正确配置和打包容器映像需要额外的知识。在这篇博文中,我将讨论 Jib 的使用,Jib 是 Google 的一个开源项目,旨在简化 Java 应用程序的工作。
我们将在这个博客中使用几种技术,并且需要对 CircleCI 有一个基本的了解。如果你是 CircleCI 的新手,我们有介绍性内容帮助你入门。
什么是 Jib?
Jib 为你的 Java 应用程序构建 Docker 和 OCI 图像,并作为 Maven 和 Gradle 的插件。
Jib 有一些有趣的价值主张。在他们的项目页面上有更详细的描述。也就是说,它降低了将独立的 Java 应用程序转变为完全可移植的 Docker 映像所需的复杂性和时间。我们的示例应用程序是一个 Spring Starter web 应用程序,但是该项目支持任何基于 Java 的应用程序,并对任何所需的定制提供了强大的支持。除了核心库,该团队还为 Maven 和 Gradle 共享插件,以无缝集成到您现有的构建流程中。
先决条件
为了跟随这个演示,你需要一个 Docker 注册的帐户。我将使用 Docker Hub,但也支持许多其他产品,包括 Artifactory、Nexus 和 GCR。
我们的示例应用程序
我正在使用一个来自 Spring Initializer 的示例 Java 应用程序。我已经在 https://github.com/eddiewebb/circleci-jib-demo 的分享了完整的项目,如果你想直接进入代码或者跟随的话。在继续之前,请确认您的应用程序在本地运行。对于 Spring Boot 应用程序,这非常简单:
mvn spring-boot:run
示例项目和博客文章使用了 Maven 插件,但是如上所述,Gradle 是完全受支持的。
运行臂
Jib 通过设置一些合理的缺省值,包括一个基本的发行版映像,减少了所需的样板配置。Jib 甚至会在启动应用程序时推断出合适的类作为入口点。
如果您想在本地测试,您可以直接构建到 Docker 守护进程中。
mvn clean compile com.google.cloud.tools:jib-maven-plugin:0.9.7:dockerBuild
您可以用以下方式来旋转它:
docker run -p 8080:8080 java-jib-demo:0.0.1-SNAPSHOT
注意:8080
是 Spring Boot 应用程序的默认端口。根据你的起点可能会有所不同。
将 Jib 图像推送到注册表
使用 Jib 的好处之一是我们实际上不需要 Docker 守护进程。我们可以构建一个图像并直接发布到公共/私有注册中心。因为注册中心需要认证,所以让我们设置 Maven 项目来使用 Docker Hub 凭证。(Docker Hub 是默认注册表,如果您使用替代注册表,请参见配置指南)。
在您的 Maven 的settings.xml
(通常在<HOME>/.m2/settings.xml
中找到)中,为 Docker Hub 注册表定义一个服务器块,其中包括您的 Docker 用户名和密码:
用明文设置密码从来都不是一个好主意,当然也不是我们希望在代码库中出现的东西。在下面的“启用 CircleCI 部署”一节中,我们将设置 Maven 加密。
配置好凭证后,您需要提供的唯一其他信息是通过传递-Dimage
使用的结果 Docker 映像名称。
让我们把创建的图像保存在本地。为此,我们将使用jib:build
目标:
mvn clean compile com.google.cloud.tools:jib-maven-plugin:0.9.7:build -Dimage=eddiewebb/hello-spring
一旦构建完成,你会发现一个全新的形象坐在你的注册表中。
配置起重臂
除了琐碎的应用程序,您还需要对生成的图像进行修改。幸运的是,Jib 提供了几个配置参数,可以直接放到你的pom.xml
中。
为了让我们的版本控制保持一定的纪律性,我们不能发布每个带有默认“最新”标签的图像。使用配置中的<to>
元素,我们可以完全指定位置和标记。
属性build.number
是我们将传入的与 CircleCI 构建标识符相关的内容。添加一个默认值以保持本地开发的简单性,即000
。
您将注意到其他几个属性,包括提交散列和工作流 ID。这些只是每个 CircleCI 作业可用的几个环境变量。我们将把它们作为附加属性,传递到应用程序中,以显示正在运行的应用程序的重要构建信息。为了在 JVM 中设置这些值,我们将使用另一个配置块<jvmFlags>
。
您可以在项目页面上找到其他配置参数。
在配置 CircleCI 之前,让我们最后一次验证我们的配置。
现在,访问http://localhost:8080/build-info,您将看到演示应用程序如何公开我们传入的附加 JVM 标志。
让我们使用 CircleCI 来为可重复和确定性的构建自动化这个过程,实现端到端的可追溯性。
加密 Maven 凭证
首先要解决的是凭证管理。我们不会将任何敏感的凭证签入源代码,但是我们的 CircleCI 构建需要访问它们。有几种方法可以解决这个问题,我的例子结合使用了 Maven Encryption 和 CircleCI 环境变量。
加密“主”密码:
mvn --encrypt-master-password
Master password: <<type some random but lengthy string as input>>
{sqtg2346i10Hf2Z1u9bYgyDxooiIa6AXlBY92E5x+2dvqsCU7kI+iM9b8lI42Thh}
将结果保存在 Maven 主目录下名为 settings-security.xml 的文件中,即~/.m2/settings-security.xml
。
加密您的 Docker 注册表密码:
mvn --encrypt-password
Password: <<your Docker registry credentials>>
{9Z0In9ZySLsH7re5LlnGsvstLmfGfHL+7vi92maAXGiZ4oBP1iGwdoXR7QElP3TU}
用生成的密码更新 settings.xml:
此时,您可以运行
mvn clean compile jib:build
再次确认加密的凭证正在工作。
设置 CircleCI
通过访问https://app.circleci.com/dashboard并按照提示“开始构建”您的项目库,将您的项目添加到 CircleCI。
第一次构建将会失败,因为我们还没有完成项目的配置。为了让它通过,您需要访问项目的配置页面,并添加一个名为maven_security_master
的变量,该变量包含您在前面步骤中的主密码。我们的 .circleci/config.yml
使用该变量在我们的构建中重新创建关键的settings-security.xml
文件。
您还需要将您的~/.m2/settings.xml
复制到项目.mvn/wrapper/
文件夹中。CircleCI 可获得settings.xml
和主密码以正确上传,这一点很重要。
准备好settings.xml
文件后,提交您的最新变更并将其推送到您的存储库中。CircleCI 应该开始建立并成功发布您的 Docker 图像。
一旦发布,如果您运行我们新生成的图像,您将看到我们从 CircleCI 的执行环境传递的所有值,这些值显示在/build-info
url 上,为您的应用提供了端到端的可追溯性!
如果您想将 CircleCI 工作流提升到一个新的水平,并开始将您的容器化应用程序部署到 ECS 或 Kubernetes,请务必查看我们系列的下一篇博客文章,并观看我们之前录制的与我们的解决方案工程师 Chris Black-Docker Deployments 102的网络研讨会。
快乐大厦!
不要让代码冻结让你置身于寒冷的环境中
原文:https://circleci.com/blog/don-t-let-code-freeze-leave-you-out-in-the-cold/
来自出版商的说明:您已经找到了我们的一些旧内容,这些内容可能已经过时和/或不正确。尝试在我们的文档或博客中搜索最新信息。
代替部署要做的 7 件事
每年的这个时候,许多公司都会实行“代码冻结”,在一段时间内停止新的部署(通常是为了等到假期零售高峰结束,或者直到团队在假期后全部回到办公室)。
虽然在此期间新特性可能不会发布给客户,但这并不意味着有意义的工作不会在工程团队中发生。这是一个充满规划、路线图和为来年的成功组建团队的时期。对于个人或团队范围的试验、目标设定和现有系统的微调(例如,从 CircleCI 1.0 迁移到 2.0 )来说,这也是一个富有成效的时间。在自然界中,冬天是休息和重置的时间。在我们这个生产力近乎恒定、24 小时都有空闲通知的工作世界里,一年中抽出一些时间来放松和反思也是一件好事。
因此,不管代码冻结是否在你的工作场所成为现实,今年 12 月花点时间想想你的长期目标,你想学习的技能,或者你想在你的代码库和你更广泛的工作生活中做出的改变。
虽然没有限制,但这里有七条建议可以帮助你开始:
1。磨练自己的技能。也许这意味着学习一门你一直好奇的新语言(也许是仙丹或铁锈)。设定您的目标并构建一个示例项目。或者,为了在假期倒计时时保持思维敏捷,请查看降临代码并完成各种技能水平的挑战性编码难题。当新的一年开始时,你将准备好应用你的新知识。
2。向前支付。许多组织需要愿意分享励志故事、教学和指导的计算机科学专业人员。用 12 月份的时间想想明年你想在哪里做志愿者。你不需要成为专家来提供服务!查看 ClojureBridge 、 Code2040 或其他致力于提高技术无障碍的组织。如果你想为一些开源项目做贡献,探索 24 拉请求以获得建议的项目和制作你的第一份 PR 的有用指南。
3。举行黑客马拉松。召集你的团队,发挥创意。在你的代码库之外开发一些东西,并一起构建一个原型,这是建立友谊、相互学习、为 2018 年的新产品可能性感到兴奋的好方法。
4。作为一个团队走到一起。花些时间与你的团队分享你对共同完成的事情的感激,并为来年制定一些新年计划。例如,设定一个向无过失尸检努力的意图。或者确保在会议中听到所有的声音(即使是安静的声音)。
5。扩大覆盖面。将代码覆盖率和林挺工作添加到您的 CircleCI 构建中。查看 Codecov 或 Hound CI 。
6。打开你的门。来年,你的工作场所能否举办一次聚会?许多团体,尤其是新成立的团体,很难找到会议室或资金来源。如果你有空间,考虑主持或赞助当地的工程会议。你将帮助社区,建立联系,通常还有披萨。
7 .。微调你的系统。利用这段时间对您现有的基础设施进行必要的更改,以便在新的一年里顺利投入使用。为了改进您的 CI/CD 管道,请测试 CircleCI 2.0。您的团队可以在您的配置中安全地测试它,同时在您测试 2.0 时保持 master 在 1.0 上运行。在这里了解所有关于移民的信息。
无论 12 月给你的组织带来了什么,我们希望你能找到时间来反思和欣赏你今年取得的成就,规划富有成效的 2018 年,并享受一些与家人和爱人在一起的时间。我们在这里尽我们所能帮助你,确保你在 2018 年有一个良好的开端!
你不需要从詹金斯迁移。在它旁边开始建造。圆环
十年前,像 Jenkins 这样的工具是你的 CI 管道的一流自动化平台。从低级工具和定制脚本到像 Jenkins 这样的工具的跳跃带来了巨大的改进。现在,新一代基于网络的工具已经问世。它们为产品构建自动化的下一次飞跃提供了一个平台。
这一悠久的历史意味着许多成熟的组织将 Jenkins 用于 CI。项目开始时的最佳选择, Jenkins 仍然是一个称职的工具,但它需要配置和管理软件和端点。
团队进行了大量投资来创建针对其需求和要求的 Jenkins 工作流。引人注目的现代工具是可用的,但从詹金斯大规模迁移似乎是复杂和昂贵的。
还有一个选择。你不需要替换已经运转良好的詹金斯。相反,随着您添加新的应用和微服务,逐渐迁移到现代 CI 工具。
詹金斯是什么?
Jenkins 支持软件测试和构建自动化,这是我们现在称之为 DevOps 的一部分。它需要一台物理机或虚拟机以及一个链接到其他系统的受管理端点。
Jenkins 的一个关键特性是扩展其功能和报告的插件。插件使 Jenkins 能够跟上不断变化的开发环境。考虑这个 Jenkins 脚本,它使用了一个 Docker 插件:
/* Requires the Docker Pipeline plugin */
node('docker') {
checkout scm
stage('Build') {
docker.image('node:14-alpine').inside {
sh 'npm --version'
}
}
}
从詹金斯迁移
Jenkins 是一个成熟而强大的工具,它试图跟上快速而普遍的向云技术转移的步伐。被新一代 CI 工具吸引的开发人员可能会觉得使用这种旧技术很困难。
从 Jenkins 迁移一个复杂的过程是困难的,并且可能是昂贵的,尤其是对于已经存在五年或更长时间的系统。和往常一样,采用新工具有一个学习曲线。错误会导致操作中断。
团队在创建复杂的 Jenkins 管道上投入的时间和精力必须转化为不同的格式。不可避免的是,一些函数和语句缺乏对等性,需要在新平台上仔细重构。
Jenkins 本质上仍然是一个 CI 工具,因此部署步骤很难迁移。虽然插件帮助它适应连续交付,但每个插件都需要单独的配置。如果不手动重新创建所有内容,该配置不容易移植到其他 CI 工具。
现代持续集成工具的优势
如果 Jenkins 已经在工作了,为什么一个企业会考虑迁移到现代 CI 工具呢?
现代 CI 工具的一个好处是速度。Jenkins 基于插件的架构非常强大,但是核心功能的缺乏导致 CI 应用程序不能总是快速满足开发人员的期望。其他更新的工具可以更快地构建、测试和部署应用程序和环境。
现代 CI 工具的另一个好处是减少了维护时间。Jenkins 是开源和免费的,但是有人必须花时间在物理或虚拟机上安装和维护安装。Jenkins 可能需要外部端点,因此还有一个网络方面。
无论您是为外部支持付费还是为内部员工付费,维护都是一笔不容忽视的费用。当你考虑所有的成本时,现代的基于网络的 CI 工具要比像 Jenkins 这样的传统工具便宜得多。
管理插件蔓延是另一个需要考虑的问题。现代 CI 工具内置了广泛的现代工作流。您将获得一个能够在云原生开发和部署环境中运行的 CI 系统,而无需安装许多插件。例如,不再需要插件来支持像 Git 和容器这样的基础,现代 CI 工具本身就支持它们。
新工具大放异彩的另一个领域是调试。当您的 CI 渠道出现问题时,最新的 CI 工具提供了对渠道的可见性,以确定问题所在。这种能见度在詹金斯更有限。
高级通知是现代 CI 工具的另一个优势领域。当出现流程错误或中断时,可以通过实时通知及时联系相关人员。插件可能会填补这些空白,但这样你就有了另一个组件来支持。
在当今的云原生世界中,分析很常见。大多数现代 CI 工具在中内置了有用的分析,因此您可以看到关于您的构建-测试-部署管道的各种有用信息。
现代 CI 系统比传统工具更易于管理。首先,基于云的工具消除了构建和维护基础设施的需要。此外,默认情况下,现代 CI 系统具有可扩展性和高可用性,让您不再担心。
组合管道
当您运行 Jenkins 等传统工具时,如何开始使用现代 CI 工具?一种方法是在添加新项目或服务时开始使用现代 CI 工具。
您可以保留现有流程,学习新工具,并开始以有组织且无中断的方式进行迁移。您的 Jenkins 管道可以继续运行,无需修改。
随着您的团队越来越熟悉现代 CI 工具,您可以考虑迁移现有的 Jenkins 项目。您可能希望使用一个组合管道逐步开始。例如,您可以让 Jenkins 继续做它最擅长的事情——构建您的复杂应用程序——然后让一个现代的 CI 工具接管像将应用程序容器化并将其部署到 Kubernetes 集群这样的任务。
CircleCI 支持流行的版本控制系统,运行在干净的容器或虚拟机中,具有自动通知、用 SSH 调试,可以将项目部署到许多环境中。分析(洞察)也是内置的。仪表板看起来像这样。
一种方法是在 CircleCI 中创建新的管道,然后使用 CircleCI API 通过 Jenkins HTTP 请求插件触发该管道。一旦在 Jenkins 实例中安装了新管道,就可以构建一个对 CircleCI API 的 GET/POST 请求。
CircleCI API 使用一些类型的认证,包括“basic_auth ”,您可以在 Jenkins HTTP 请求插件中配置它。你可以在 CircleCI 文档中了解如何触发管道。Jenkins 请求示例(不包括授权头)可能如下所示:
httpRequest acceptType: 'APPLICATION_JSON', contentType: 'APPLICATION_JSON', requestBody:
'''{
"branch": "feature/design-new-api",
"tag": "v3.1.4159",
"parameters": {
"deploy_prod": true
}
}''', responseHandle: 'NONE', url: 'https://circleci.com/api/v2/project/gh/CircleCI-Public/api-preview-docs/pipeline', validResponseContent: '201', wrapAsMultipart: false
使用这种技术,您可以继续从 Jenkins 驱动您的流程,同时开始将操作迁移到 CircleCI。
说到迁移, CircleCI Jenkins 转换器帮助您将 Jenkins 操作转换为 CircleCI。它处理越来越多的插件和 Jenkins 语法。
开始整合新的 CI 工具
既然您已经了解了现代 CI 的好处以及 CircleCI 的适用范围,为什么不试一试呢?立即注册 CircleCI 免费试用以简化您的开发工作,并让您的团队迁移到现代云。
由 CircleCI 首席软件工程师 Pat Shields | CircleCI 主持的冗长对话
在这一集的《冗长的对话》中,我们将谈论一些与我们的心息息相关的东西——circle ci。我们和 Spotify、脸书、福特和 Aetna 等公司成千上万的其他开发人员一起,每天都在使用 CircleCI,以确保我们部署了高质量的代码,并在我们的工程流程中提高了效率。
但是,我们的平台下面到底是什么呢?
加入我们的首席技术官 Rob Zuber,他将主持 CircleCI 的首席软件工程师 Pat Shields,讨论我们的技术和平台的内部工作方式。他们讨论从产品功能到架构的一切,并谈论我们平台的核心元素是如何以及为什么构建的。
Rob 甚至轮流与标记讨论领域驱动的设计、认证等等。在今天的对话中,了解你想知道的关于 CircleCI 的一切。
</blog/media/2020-05-15-drawn-out-pat-shields.mp4>
与 Okta 技术总裁的对话| CircleCI
安全性和双因素身份认证在我们的日常生活中变得越来越根深蒂固,尤其是在工作中。如果你的工作涉及登录云服务,你很可能遇到过 Okta ,这是一个单点登录工具,允许团队验证用户进入他们每天依赖的数字工具动物园。
在这一集的《冗长对话》中,CircleCI 首席技术官 Rob Zuber 欢迎 Okta 的技术总裁 Hector Aguilar 来到演播室,与我们一起探讨(并绘制)为技术世界提供动力的认证引擎。Hector 通过 Okta 的体系结构与 Rob 进行了对话,并分享了他的团队是如何在运行全世界所依赖的软件所需的代码中获得信心的。
这一集既有趣又有教育意义,因为 Rob 和 Hector 的对话从身份验证到负载平衡器,再到为什么旧 API 永远不会消失,等等。
</blog/media/2019-11-18-drawn-out-okta-hector-aguilar.mp4>
与 Turo CTO | CircleCI 的对话
原文:https://circleci.com/blog/drawn-out-conversations-featuring-turo-cto-avinash-gangadharan/
不是每个人都适合拥有汽车。无论是费用、想避开交通、在城市里找停车位的头疼,不是每个人都想拥有一辆车。但是,我们都不时需要一个。这就是世界上最大的汽车共享市场 Turo 的用武之地。在这个市场上,客人可以从遍布美国、加拿大、英国和德国的充满活力的本地主机社区预订任何他们想要的汽车,无论他们想去哪里。车主可以抵消拥有成本,客人可以无忧无虑地上路。
在这一集的冗长对话中,CircleCI 首席技术官 Rob Zuber 在 Turo 欢迎 Avinash Gangadharan 首席技术官,讨论这项服务及其架构,以及该公司如何为其所有者和客人社区提供服务。
</blog/media/2020-02-27-drawn-out-turo-avinash-gangadharan.mp4>
DevSecOps -安全 CI/CD -移动目标防御| CircleCI 和 CryptoMove
原文:https://circleci.com/blog/dynamically-pull-in-your-stored-sensitive-data-with-the-cryptomove-orb/
DevSecOps 可以定义为 DevOps 的长期实践,将系统的安全性作为中心租户。使用传统的 DevOps,开发人员已经找到了使软件开发生命周期变得更加容易的方法。一个常见的实践是持续集成和持续部署(CI/CD ),它自动化了测试和部署新版本代码的手动步骤,节省了无数的工程时间,这些时间可以用于进一步增强产品。
虽然 DevOps 理所当然地获得了许多软件开发团队的关注,但是安全性经常被忽视,因为它“妨碍了”发布特性。DevOps 在某种程度上与安全性相冲突的这种范式已经导致了薄弱的软件实践,比如将应用程序秘密存储在代码中,或者允许公司中的任何人查看构建。因此,DevOps 引入了新的威胁媒介,使公司及其专有软件和数据变得不必要的脆弱。例如,Jenkins,一个团队常用的开源 CI/CD 服务器,已经成为黑客攻击的目标。
我们建议不要认为开发运维的实践是针对开发速度的,安全应该被认为是团队发布新版本软件的主要租户,因此有了术语 DevSecOps。速度虽然重要,但如果它意味着你所有的努力都落入坏人之手,那就没有意义了。此外,实施安全最佳实践并不像人们通常认为的那样耗费时间或资源。
为了节省时间和提高安全性,您可以使用第三方 CI/CD 提供商(如 CircleCI)和数据安全供应商(如 CryptoMove)来部署您自己的 DevSecOps 管道,其资源比 Jenkins 服务器少得多。CryptoMove 的工作原理是通过移动目标防御来存储您的敏感数据,这是一项使您的数据保持移动的专利技术,使攻击者更难锁定它。CirlceCI 通过管理您的构建和部署服务器来工作,因此您所需要的只是一个在 YAML 编写的配置文件,它声明了用于测试和部署您的软件新版本的命令。CircleCI 和 CryptoMove 都可以“本地”部署,这利用了公司的网络来增加安全性。
你可以将 CryptoMove 和 CircleCI 与 CryptoMove orb 一起使用。有了这个 orb ,你可以在 CryptoMove 中存储 API 秘密和数据库密码等敏感数据,并在 CircleCI 构建和部署中动态地提取它们。CircleCI 作业是短暂的,这意味着在构建完成后,您的敏感数据会被垃圾收集。这消除了黑客以前用来访问敏感信息的关键攻击媒介。
与所有安全性一样,无论是物理安全性还是代码安全性,一个良好、可靠的基础设施都需要实现许多迭代步骤来保护您的数据。然而,这并不意味着实现这些控制会妨碍您的软件开发生命周期。相反,您可以用一个健壮的 DevSecOps 范例来完成这两个任务。
这篇文章是我们制作的关于 DevSecOps 的系列文章的一部分。要阅读本系列的更多文章,请单击下面的链接之一。
动态呈现用于秘密管理的配置模板
原文:https://circleci.com/blog/dynamically-rendering-config-templates/
通常有必要在构建或部署过程中注入秘密,以便部署的服务可以与其他服务交互。如果您只部署到单一环境,这可能很简单。但是,当部署到多个环境时,您可能需要根据您要部署到的环境动态地注入不同的秘密。
假设您的应用程序中有一个虚拟机(VM)。该虚拟机需要一个嵌入在配置文件中的秘密 API 令牌来与第三方服务通信。为了保持生产和非生产环境的隔离,您为生产服务器创建了一个“prod”API 令牌,为非生产服务器创建了一个“dev”API 令牌。现在,您不希望将这些令牌硬编码到配置文件中,并将其签入您的版本控制系统(VCS),原因有两个。首先,因为将秘密签入源代码控制是不安全的做法,其次,因为您不想维护这个配置文件的单独的“prod”和“dev”版本。更好的解决方案是动态生成带有正确令牌的配置文件,并将其注入到 CI/CD 管道作业中。但是这带来了几个新的挑战:
- 如何安全地存储和访问机密
- 如何动态呈现配置模板
- 如何在渲染后注入模板
在这篇文章的下一部分,我们将讨论这些挑战的一些解决方案。
安全地存储和访问机密
这里的挑战是双重的:首先,如何安全地存储您的秘密?第二,如何使它们能够被 CI/CD 管道中呈现模板的流程访问?
用 CircleCI 上下文管理秘密
CircleCI 有一个内置的秘密存储,可通过我们的上下文功能访问。记录在上下文中的机密具有以下属性:
- 它们存储在 Hashicorp 的保险库中,使用 AES256-GCM96 加密,CircleCI 员工无法访问(链接)。
- 可以使用 CircleCI CLI 自动旋转它们。
- 它们的键和值在创建后不能修改。
- 它们的值不能在 CircleCI 管道作业之外公开。
提示:如果您的秘密只在 CircleCI 内部使用,请使用 CircleCI 的上下文。
在 CircleCI 管道作业的配置中,可以指定一个或多个要加载的上下文。这些上下文中的秘密将在该作业的持续时间内作为环境变量变得可用。然后,您可以让模板呈现引擎将这些环境变量中的数据插入到配置文件模板中,以呈现适合目标部署环境的配置文件。
使用第三方秘密存储
另一种选择是使用第三方秘密存储,如 SecretHub 、AWS Secrets Manager 或 Hashicorp Vault。这些更灵活,因为它们的秘密可以用于 CircleCI 以外的服务。然而,要在 CircleCI 中使用它们的秘密,您需要编写自己的方法来提取这些秘密,并使它们对您的模板渲染引擎可用。你也许可以利用 CircleCI 的合作伙伴和社区 orbs 来帮助整合这些工具。
动态呈现配置模板
您对模板渲染引擎的选择取决于几个因素,包括:
- 您用于构建和/或部署的工具
- 应用程序中使用的语言
- 您的团队最习惯使用的模板语言
提示:对于需要多个工具访问的秘密,可以考虑第三方秘密存储。预算时间来编写逻辑,使秘密可用于您的模板渲染引擎。
如果你使用 Terraform,你可以使用它的字符串模板语法。如果你使用 Python 或 Ansible,你可能会使用樱井真子或金贾模板。在这两个例子中,您可以使用 CircleCI 预构建的图像,为包含模板渲染的作业预安装 Terraform、Ansible 或 Python,从而节省一些时间。你也可以查看任何相关的宝珠,比如金贾宝珠。
一旦您将配置文件模板签入到 VCS 中,并向管道的部署作业添加了使用您选择的模板呈现引擎来呈现模板的步骤,您只需确保您将注入到模板中的秘密对您的模板呈现引擎可用。如前一节所述,CircleCI contexts 使这变得容易。如果您使用的是第三方秘密存储,您需要编写一些脚本来安全地检索秘密,并将它们传递给模板呈现引擎。
提示:使用方便的图像和球体来减少设置模板渲染环境的工作量。
将渲染模板注入管道
因此,您已经在管道中呈现了模板,现在您需要将它们注入到管道作业中。这一部分听起来可能很简单:只需呈现模板并将它们插入到您的构建工件中,或者将它们推送到在您的部署过程中创建的基础设施中
但是,在使用渲染模板的同一作业中渲染模板并不总是可行的。假设您正在呈现想要注入到 Docker 映像构建中的 Jinja 模板化的配置文件。用于渲染 Jinja 模板的最方便的 CircleCI 执行器是一个 Docker 容器,它运行 CircleCI 的 Python 便利图像。构建 Docker 映像最有效的执行器可能是一个机器执行器(换句话说,一个 VM)。每个作业都在一个干净的容器或 VM 中运行,所以 Docker 容器中呈现的模板对于运行 Docker 构建的机器执行器是不可用的。您可以将这两个任务合并成一个管道作业,在两个执行器中的一个上运行,但是这会使您的管道更慢、更复杂。
提示:缓存渲染后的模板,供管道中的其他作业使用。
幸运的是,CircleCI 允许您缓存工作空间中作业之间的依赖关系。您可以渲染模板,将其缓存在工作空间中,然后将该工作空间附加到需要使用这些模板的任何后续作业。这使您能够为每个作业使用最有效的执行器(就配置工作和计算时间而言)。
动态呈现配置模板解决了安全存储机密的问题,同时保持 CI/CD 管道中的进程可以访问它们。在本文中,我介绍了如何使用 CircleCI 上下文或第三方秘密存储安全地存储和访问秘密。我还介绍了如何选择模板呈现引擎,以及如何使用该引擎将秘密注入配置模板。使用动态呈现模板应用机密管理的最佳实践将有助于保持 CI/CD 管道成功安全地运行。
边缘计算与云计算| CircleCI
原文:https://circleci.com/blog/edge-computing-vs-cloud-computing/
到目前为止,几乎每个人都以某种形式熟悉云计算。在整个 2010 年代,云计算的概念在软件行业内不断发展,然后作为一个普遍的家庭术语进入日常生活。
边缘计算的概念不太为人所熟悉。“edge”的起源可以追溯到 20 世纪 90 年代的第一个内容交付网络。从那时起,边缘概念就主要是网络工程师的领域。边缘计算最近得到了认可,人气飙升,成为了分布式计算新世界中的一个重要概念。
什么是边缘计算?
边缘的概念是关于物理距离的。edge 通过消除尽可能多的往返时间来最大限度地减少延迟并提高性能。边缘计算通过将网络连接定向到相对于终端用户的物理位置最近的边缘计算节点来实现这一点。
从根本上说,这与内容交付网络(CDN)是同一个概念。但是,CDN 的主要目标是加速图像和视频等静态资产的传输,而边缘计算则专注于处理尽可能靠近最终用户的硬件资产上的代码。
边缘计算可以为要求速度和性能的苛刻应用提供显著的性能提升。由于边缘计算节点比服务器或数据中心数量更多、分布更广,利用边缘计算的应用程序可以为全球用户提供最小的延迟。此类应用还提供了将边缘节点集中在特定服务位置以实现无与伦比的性能的机会。
边缘计算节点采用虚拟机(VM)和容器的形式,运行在战略定位的服务器上,选择这些服务器是因为它们靠近终端用户的集中点。流行的边缘计算提供商 StackPath 采用了这种方法。
另一种方法依靠无服务器方法来执行特定代码,而无需专用服务器。例如, Cloudflare Functions ,允许代码在 Cloudflare 网络上的不同位置运行,而无需专用服务器。
边缘计算和云计算的区别
尽管我们已经在这里定义了边缘计算,但是边缘和云计算概念之间仍然有一些重叠。这两种想法都涉及使用远程分布式计算资源来执行任务和代码。从这个意义上说,边缘计算可以被认为是云计算的一个子集,但有一些关键的区别。
优势概念的本质是速度和性能。虽然云是一种多工具,提供各种各样的服务和选项,但边缘计算的关注点要窄得多。它优先考虑最小化延迟,而不是最大化性能。
边缘计算的基础设施反映了这种差异。虽然云和边缘计算都依赖于分布式服务器网络,但边缘计算基础设施需要更多数量的存在点(pop ),这些 pop 配备了比典型云服务器更强大的硬件。边缘 pop 需要能够处理各种性能敏感型边缘应用的计算负载的高级基础设施。
尽管这两者之间存在着重大差异,但边缘和云计算的概念并不相互对立。两者结合使用,可以优化企业应用的性能。高性能和延迟敏感的任务发生在边缘 pop 上,而要求较低的工作发生在云中的其他地方。
边缘计算使用案例
因为边缘计算通过最大限度地减少延迟来提高性能,所以用例往往是高要求的应用程序或大多数最终用户居住在特定地理位置的应用程序。
也许边缘计算用例的最佳例子是多人游戏。现代视频游戏通常是高要求和资源密集型软件,对于玩家的机器和促进在线游戏的服务器都是如此。延迟必须最小,以创建一致的玩家体验。因为多人游戏通常将来自不同地理位置的玩家联系在一起,所以 edge POPs 是消除延迟和创建流畅体验的理想解决方案。
边缘计算的其他使用案例不太关注极端的硬件性能,而是纯粹通过地理上的接近来提供改进。拼车或餐馆外卖应用等服务往往有一个专注而一致的最终用户服务区域。尽管这些服务可能对个人要求不是特别高,但通过确保这些应用在终端用户附近的 edge POPs 上运行代码,服务的整体质量和性能可以显著提高。
扩展边缘项目的 CI/CD
从持续集成和持续部署(CI/CD) 的角度来看,云和边缘区别不大。为了创建 edge POPs,服务提供商巧妙地将硬件部署放在服务接收方附近。用户可以使用在云中或内部环境中启用 CI/CD 的相同工具来更新和维护它们。
云和边缘的一个显著区别是硬件的数量。Edge POPs 的数量肯定远远超过简单的云服务器或数据中心。因此,边缘计算是 CI/CD 的理想使用案例。CI/CD 管道中提供的自动化大大减少了将新代码部署到 edge POPs 所需的工作量,否则可能需要有人手动更新数十甚至数百个环境。
向边缘移动
对于需要无法容忍额外延迟的性能的软件,或者对于在高度本地化的服务区域中运行的应用程序,边缘计算提供了传统云服务所缺乏的实质性优势。
有了合适的工具(比如持续流动的 CI/CD 管道),将服务转移到边缘的路线看起来就像部署到其他地方一样。主要关注的是架构,只有适当的代码和服务应该转移到 edge POPs。要求较低的服务通常可以保留在云中,由 edge POPs 处理繁重的工作,同时与其他云或内部资源进行通信。
最终用户看不到正确的边缘部署。使用适当的方法,对于负责部署的组织和开发运维团队来说,边缘可能只是一个脚注。随着网络变得越来越大,软件变得越来越互联,我们可能会看到可用的 edge POPs 的数量继续增长。对边缘服务的依赖将成为更常见的部署策略。
它不是云计算和边缘计算争夺霸权的案例。相反,将边缘视为云的自然延伸。
要了解有关使用 CI/CD 管道优化部署到云和边缘环境的更多信息,注册一个免费的 CircleCI 帐户并立即开始构建。
为电子应用程序配置自动化构建| CircleCI
Web、移动和桌面是三个最流行的软件应用平台。 Electron.js 的出现使得为所有这三个平台开发跨平台应用成为可能。随着 HTML、CSS 和 JavaScript 成为网络的默认语言,开发人员现在可以通过使用相同的技术来构建移动应用程序(由 Cordova 项目实现)和桌面应用程序,从而扩展他们的应用程序开发范围。在本文中,我们将配置一个持续集成(CI) 管道来为不同的操作系统构建桌面应用程序的分发副本。
先决条件
要遵循本教程,需要做一些事情:
- JavaScript 的基础知识
- 安装在您系统上的 Node.js (版本> = 11)
- 一个圆的账户
- GitHub 的一个账户
- 熟悉 Electron.js (不是交易破坏者,但会很好)。
安装并设置好所有这些之后,让我们开始吧。
创建一个简单的电子项目
让我们通过运行以下命令快速构建一个简单的 Electron.js 应用程序:
npx create-electron-app my-electron-app
在上面的命令中,我们使用npx
调用create-electron-app
实用程序在文件夹my-electron-app
中构建一个新的 Electron.js 应用程序。我们使用create-electron-app
是因为它有助于搭建一个预先打包了 electron-forge 的 Electron.js 应用程序,该工具用于打包和创建我们的 Electron.js 桌面应用程序的发行版本。
注意 : 你不需要全球安装create-electron-app
才能使用。这就是我们使用npx
的原因。
一旦搭建过程完成,进入项目的根目录(cd my-electron-app
)并运行以下命令来启动桌面应用程序:
npm start
这将为您当前的操作系统运行一个本地构建,并启动桌面应用程序。
上面的屏幕显示了打开的开发工具。这不是你在生产中想要的。注释掉文件src/index.js
中的下面一行以阻止它打开。
mainWindow.webContents.openDevTools();
然后在运行应用程序的 CLI(命令行界面)上点击Ctrl + C
终止应用程序运行。然后再次运行npm start
重新启动应用程序。
现在,如上面的屏幕所示,只有我们的应用程序屏幕显示在应用程序窗口中。
配置构建平台
如前所述,搭建的项目已经与electron-forge
打包在一起,这是一个可以帮助我们从我们的应用程序中产生发行版本的包。在我们的例子中,我们将为Linux
平台创建一个可分发的.zip
版本,为基于 Debian 的 Linux 发行版(如 Ubuntu)创建一个.deb
包。
要对此进行配置,用以下配置替换package.json
文件中的config
部分:
"config": {
"forge": {
"packagerConfig": {},
"makers": [
{
"name": "@electron-forge/maker-zip",
"platforms": [
"linux"
]
},
{
"name": "@electron-forge/maker-deb",
"config": {}
}
]
}
},
electron-forge
包使用许多称为makers
的内部工具为不同的平台创建发行版本。makers
为 MacOS、Windows 和 Linux 平台创建发行版本而存在。在上面的文件中,我们配置了两个makers
、maker-zip
和maker-deb
,分别为 Linux 生成.zip
文件,为基于 Debian 的平台生成.deb
文件。
关于为不同平台配置makers
的更多信息,请访问制造商文档页面。
现在我们有了完整的electron-forge
配置来创建我们的发行版本。
将项目连接到 CircleCI
我们的下一个任务是在 CircleCI 上建立我们的 Electron.js 桌面应用程序项目。从将你的项目推送到 GitHub 开始。
接下来,转到 CircleCI 仪表板上的添加项目页面。
点击设置项目开始。
在设置页面上,单击手动添加以指示 CircleCI 我们将手动添加配置文件,而不使用显示的示例。接下来,您会得到提示,要么下载管道的配置文件,要么开始构建。
点击开始建造。这个构建将会失败,因为我们还没有设置配置文件。这一点我们将在下一节中介绍。
自动化发行版构建并存储构建输出
是时候写我们的 CI 管道了。我们的管道需要完成以下操作:
- 签出存储库
- 更新 npm
- 安装项目依赖项
- 为目标构建安装系统依赖项(
.deb
包需要两个系统包;dpkg
和fakeroot
,为生成.deb
文件而安装) - 生成构件
- 将可分发的构建文件存储为可以下载的工件
在项目的根目录下,创建一个名为.circleci
的新文件夹。在这个文件夹中,创建一个名为config.yml
的文件,并在其中输入以下代码:
version: 2.1
jobs:
build:
working_directory: ~/repo
docker:
- image: circleci/node:11
steps:
- checkout
- run:
name: Update NPM
command: "sudo npm install -g npm"
- restore_cache:
key: dependency-cache-{{ checksum "package.json" }}
- run:
name: Install Dependencies
command: npm install
- run:
name: Install dpkg and fakeroot
command: |
sudo apt-get update -y
sudo apt-get install -y dpkg fakeroot
- save_cache:
key: dependency-cache-{{ checksum "package.json" }}
paths:
- ./node_modules
- run:
name: Generate Builds
command: npm run make
- store_artifacts:
path: ~/repo/out/make
在上面的配置文件中,我们执行了前面列出的所有任务。让我们看一下重要的部分。
首先,我们为想要执行的操作指定工作目录。然后,我们指定 Docker 映像和所需的最少 Node.js 安装。
接下来,我们从远程存储库中checkout
项目并安装依赖项。然后我们使用管理员权限安装dpkg
和fakeroot
。
最后,我们通过运行electron-forge
包的make
命令来生成我们的配置构建。
最后,我们存储可分发的文件,它们位于一个生成的/out/make
文件夹中。
将这些更改提交并推送到您的 GitHub 存储库中。这将触发管道开始运行。你可以在 CircleCI 控制台的Pipelines
页面查看它的运行情况。
点击 build 可以查看流程详情。
如上面的屏幕所示,Upload artifacts
部分显示我们现在已经生成并存储了两个构建。
下载存储的构建工件
下载我们的构建非常容易,点击构建屏幕上的Artifacts
标签,你会看到下载你的可发布版本的链接。
您现在可以下载压缩包和.deb
安装文件。
结论
随着 Electron.js 通过支持使用 HTML、CSS 和 Javascript 创建桌面应用程序,为 web 开发人员增加了更多的超能力,感觉 web 开发人员现在几乎可以构建任何东西。这太令人兴奋了!
向最终用户分发应用程序也是这个过程中非常重要的一部分,在本教程中,我们已经看到了创建可安装的桌面应用程序,甚至使用 CircleCI 自动化打包可分发版本的过程是多么容易。
如果你没有得到你想要的结果,请再次浏览这篇文章,看看你是否遗漏了什么。
编码快乐!
Fikayo Adepoju 是 LinkedIn Learning(Lynda.com)的作者、全栈开发人员、技术作者和技术内容创建者,精通 Web 和移动技术以及 DevOps,拥有 10 多年开发可扩展分布式应用程序的经验。他为 CircleCI、Twilio、Auth0 和 New Stack 博客撰写了 40 多篇文章,并且在他的个人媒体页面上,他喜欢与尽可能多的从中受益的开发人员分享他的知识。你也可以在 Udemy 上查看他的视频课程。
电子应用 CI 自动化测试| CircleCI
Visual Studio Code ,编写时市面上最流行的代码编辑器之一, Slack ,(差不多)defacto 团队协作软件,桌面版 WhatsApp 都有共同点。都是用 Electron.js 打造的。随着这些强大的公司在本地桌面软件开发方法上采用 Electron.js,Electron.js 已经成为开发桌面应用程序的一个值得信赖的框架。在本教程中,我将演示如何测试 Electron.js 应用程序,并通过自动化测试过程更进一步。
先决条件
要遵循本教程,需要做一些事情:
安装并设置好所有这些之后,让我们开始吧。
搭建一个电子应用
首先,我们需要构建一个新的 Electron.js 应用程序。这样我们就不必从头开始制作一个新的 Electron.js 应用程序,我们将使用带有create-electron-app
包的npx
来设置它。运行以下命令创建新应用程序:
npx create-electron-app electron-test-app
这将在electron-test-app
文件夹中搭建一个新的应用程序。该文件夹可以是您想要的任何名称。
一旦该过程完成,进入项目的根目录(cd electron-test-app
)并运行以下命令来运行应用程序:
npm start
这将根据您的操作系统平台生成应用程序的临时版本,并启动应用程序。
如图所示,应用程序窗口和 Devtools 都打开了。我们不希望 Devtools 暴露出来,所以在运行应用程序的同一个 CLI 窗口中运行Ctrl + C
来终止应用程序。然后转到src/index.js
文件并注释掉下面的行。
mainWindow.webContents.openDevTools();
现在用npm start
再次运行 app。这一次,只显示应用程序屏幕,其标题包含一个“💖“表情符号,文字Hello World!"
,还有一段文字Welcome to your Electron application.
。我花时间来描述页面的内容,因为我们将很快测试这些元素。
用 Jest 和 Spectron 设置测试
下一步是建立测试框架,对我们的应用程序进行端到端测试。为此,我们需要两个主要的测试库。它们是:
- Jest :运行我们测试的 JavaScript 测试框架
- Spectron :一个用于编写端到端测试的 Electron.js 测试框架
使用以下命令同时安装这两个库作为开发依赖项:
npm install --save-dev jest spectron
一旦安装了这两个脚本,让我们继续向package.json
文件添加一个test
脚本:
{
...,
"scripts" : {
...,
"test" : "jest"
}
}
现在,我们已经拥有了在我们的 Electron.js 应用程序上运行测试所需的所有东西。
添加测试
现在是时候向我们的应用程序添加测试了。
在src
文件夹中,创建一个名为__tests__
的新文件夹。jest
在这个文件夹中找到的任何文件都将作为测试套件运行。在__tests__
文件夹中,创建一个名为AppTest.js
的新文件,并粘贴以下代码:
const Application = require("spectron").Application;
const electronPath = require("electron");
const path = require("path");
let app;
beforeAll(() => {
app = new Application({
path: electronPath,
args: [path.join(__dirname, "../../")]
});
return app.start();
}, 15000);
afterAll(function () {
if (app && app.isRunning()) {
return app.stop();
}
});
test("Displays App window", async function () {
let windowCount = await app.client.getWindowCount();
expect(windowCount).toBe(1);
});
test("Header displays appropriate text", async function () {
const headerElement = await app.client.$("h1");
let headerText = await headerElement.getText();
expect(headerText).toBe("💖 Hello World!");
});
在上面的测试文件中,我们首先需要来自spectron
包的Application
对象以及来自node_modules
包含的二进制文件的electron
。
然后,我们声明一个app
变量,并在beforeAll
函数中为其分配应用程序的一个新实例。在beforeAll
中创建应用程序的新实例后,我们通过调用app.start()
来启动它。这将在我们的任何测试运行之前启动我们的应用程序的一个新实例。我们还提供了一个15000
毫秒到beforeAll
毫秒的timeout
,以便在应用启动时间超过5000
毫秒的情况下,给我们的应用足够的启动时间(对于jest
测试套件,默认为timeout
)。
接下来,我们调用afterAll
函数,并传递给它一个在所有测试完成后停止应用程序的函数。
然后我们添加两个测试。第一个测试通过计算应用程序启动时打开的窗口数量来检查我们的应用程序窗口是否打开。如果Devtools
像我们第一次运行应用程序时看到的那样打开,我们应该有两个窗口。但是因为我们禁用了Devtools
窗口,我们应该只打开一个窗口,这是我们的应用程序开始屏幕。
第二个测试检查我们是否有一个包含字符串"💖 Hello World!"
的头(h1
)。
保存测试文件,并通过运行项目根目录下的test
脚本来运行创建的测试:
npm run test
当测试运行时,您将看到应用程序启动并闪现启动屏幕,然后在几秒钟内关闭。一旦应用程序屏幕消失,测试就完成了。
我们所有的测试都运行良好并通过了。
将项目连接到 CircleCI
我们的下一个任务是在 CircleCI 上建立我们的 Electron.js 项目。从将你的项目推送到 GitHub 开始。
接下来,转到 CircleCI 仪表板上的Add Projects
页面添加项目。
点击设置项目开始。
在设置页面上,单击手动添加以指示 CircleCI 我们将手动添加配置文件,而不使用显示的示例。接下来,您会得到提示,要么下载管道的配置文件,要么开始构建。
点击开始建造。这个构建将会失败,因为我们还没有设置配置文件。这一点我们以后再做。
自动化我们的测试
是时候编写我们的持续集成(CI)管道来自动化我们的测试过程了。在项目的根目录下,创建一个名为.circleci
的新文件夹。在这个文件夹中,创建一个名为config.yml
的文件,并在其中输入以下代码:
version: 2.1
jobs:
build:
working_directory: ~/repo
docker:
- image: circleci/node:11-browsers
steps:
- checkout
- run:
name: Update NPM
command: "sudo npm install -g npm"
- restore_cache:
key: dependency-cache-{{ checksum "package-lock.json" }}
- run:
name: Install Dependencies
command: npm install
- save_cache:
key: dependency-cache-{{ checksum "package-lock.json" }}
paths:
- ./node_modules
- run:
name: Run tests
command: npm run test
在上面的文件中,我们引入了一个Node.js
Docker 图像。注意,我们使用一个带有-browsers
后缀的图像来提供一个安装了浏览器的环境。这是因为Spectron
是建立在 WebdriverIO 之上的,它利用了Chrome/chromedriver
。指定的映像确保我们在环境中配置了一切,以使 Chrome 驱动程序工作。
然后我们更新npm
以确保我们运行的是最新版本。
接下来,我们安装依赖项并缓存它们。有了所有的依赖项,我们就可以运行测试了。
将这些更改提交并推送到您的 GitHub 存储库中。这将触发管道开始运行。这可以在 CircleCI 仪表板的Pipelines
页面上查看。
要查看流程详情,请点击构建。
我们的测试运行良好。厉害!
现在,我们可以添加更多的测试,因为我们向应用程序添加了更多的功能,并且随着每次向我们的存储库推送,我们都会触发我们的管道来自动运行所有的测试。当测试失败时,CircleCI 会通知我们,我们可以了解测试失败的原因。
结论
测试驱动开发(TDD)结合持续集成是一个晚上睡个好觉的可靠方法,知道你没有把任何错误推到你的生产环境中。在本教程中,我们演示了如何测试我们的 Electron.js 应用程序,并使用 CircleCI 自动完成测试过程。
编码快乐!
Fikayo Adepoju 是 LinkedIn Learning(Lynda.com)的作者、全栈开发人员、技术作者和技术内容创建者,精通 Web 和移动技术以及 DevOps,拥有 10 多年开发可扩展分布式应用程序的经验。他为 CircleCI、Twilio、Auth0 和 New Stack 博客撰写了 40 多篇文章,并且在他的个人媒体页面上,他喜欢与尽可能多的从中受益的开发人员分享他的知识。你也可以在 Udemy 上查看他的视频课程。
为开源贡献者提供 CI | CircleCI
原文:https://circleci.com/blog/empower-oss-contributors-with-ci/
令人惊讶的是,许多开源项目并没有实现一个持续集成 (CI)解决方案。也许你的项目就是其中之一。你可能会想,“我们不需要它,我们知道我们在做什么,”甚至,“我们太小了,我们以后再实现它。”
当维护人员使用 CI 时,它通常是一个不充分的实现,比如在没有任何测试的情况下使用它进行部署。
我应该知道;我自己也为此感到内疚。
但是我想告诉你的是,为一个开源项目实施 CI 的决定并不是关于你的。这是关于提供合适的贡献工具。它是关于用健康的代码使你的项目稳步增长。
在您的开源项目中使用 CI 将有助于授权您的贡献者更容易地制定更好的 PRs,并帮助您的项目发展壮大。
请继续阅读 CI 赋予您的开源贡献者权力的四种方式:
1.CI 将实际运行测试
这似乎是显而易见的,但值得一提。投入时间思考项目测试的维护人员需要向潜在的贡献者传达这一点。
怎么会?你可以提醒人们进行测试:
- 在
README.md
- 在
CONTRIBUTING.md
- 或者在拉式请求(PR)模板中
但是,即使采取了这些步骤,有多少人会真正阅读它们并坚持到底呢?用 CircleCI 这样的 CI 提供者运行项目测试意味着您不必担心贡献者懒惰或健忘。这是项目代码质量的安全网。
2.CI 构建失败是正常的;把它们作为一个教学点
第一次为一个开源项目做贡献可能会令人生畏。让贡献者知道 PRs 是受欢迎的,但更重要的是,他们不需要一次就做对。如果公关状态检查变成红色,太好了!您可以做的第一件事是确保用户知道如何点击 CI 提供者并检查错误(PR 页脚中的测试通过/失败链接)。不要假设任何事情。然后你可以给那个人建议如何解决问题,给他们时间去解决。这里的想法是,这是一个教学点。记住:他们可能不会像你一样以同样的速度消灭错误。贡献者可以学习并变得更强,同时这种互动为你的项目及其社区定下基调。友好相处,一起解决问题。
3.CI 允许贡献者从事他们可能无法从事的项目
我将用一个真实的例子来解释这一点。让我们看看 CircleCI CLI ,这是一个开源项目,为 macOS 和 Linux 编译。如果用户要报告一个特别影响 CLI 的 macOS 版本的错误,我可以尝试修复它。作为一名 Ubuntu Linux 用户,我可以编写代码,甚至可以交叉编译,但我无法实际测试它以确保修复工作正常。我没有苹果电脑。
进入 CircleCI。
我可以用我的补丁打开一个 PR,CircleCI 将在 macOS 机器上构建并测试它。它为我消除了一个技术障碍。同样地,CI 可以减少人们对你的项目公开 PRs 的摩擦。
4.不需要为非部署作业构建机密
当 API 令牌、SSH 密钥等。参与了一个构建,你不希望那些构建秘密落入坏人手中。这可以理解。默认情况下,CircleCI 上的公共项目在分叉 PRs 上关闭了秘密。
我们支持你。
你所能做的是努力让分叉的 PRs 达到一个绿色的构建,而不是一开始就有那些秘密。依赖于秘密的命令应该被隔离到它们自己的任务中,或者用 Bash 逻辑阻塞。通过这种方式,外部的 PR 将能够运行通过的测试,并且项目维护人员可以在master
分支或其他方式中运行集成测试或部署。
结论
一个配备了 CI 工具的开源项目降低了投稿的门槛,同时提高了整体质量。开源与人和代码一样重要。被授权的贡献者更快乐、更有效率。这有利于项目,意味着每个人都赢了。
P.S. CircleCI 给所有用户/项目一个免费的构建容器。你知道我们给开源项目,具体来说就是 4 个容器吗?还是免费的。我们一起来做软件吧!。
端到端浏览器测试| Ghost Inspector CircleCI orb
原文:https://circleci.com/blog/end-to-end-browser-testing-with-the-ghost-inspector-circleci-orb/
随着应用程序变得越来越复杂,有必要确保团队能够以一致且可重复的方式测试和交付他们的代码。测试一个基于 web 的应用程序最困难的方面之一就是应用程序本身;测试用户通过你的界面的路径是项目交付的一个关键但具有挑战性的方面。传统上,用户界面测试的设置和维护非常复杂,通常需要非常专业和有经验的技能。Ghost Inspector 通过提供简单易用的工具来解决这个问题,该工具允许团队中的任何人创建和维护基于浏览器的测试。QA 团队可以更快、更一致地交付产品,并在您的应用程序中进行更彻底的测试。
Ghost Inspector 是一个自动化的浏览器测试服务,允许您轻松地从云中创建、管理和执行测试。我们的工具允许您使用真实的浏览器记录和回放测试,以可测试和可重复的方式重现最终用户的行为。
轻松执行 Ghost Inspector 测试套件
我们开发的 orbs 允许您通过几行配置将 Ghost Inspector 集成到您的 CircleCI 工作流中,将我们基于浏览器的测试解决方案的强大功能带到您的部署工作流中。团队中的任何人都可以轻松地记录和管理测试,并直接存储在我们基于云的平台上,以便于执行。您可以利用我们的 orb 在您的部署管道中执行单个测试或一整套测试。测试可以在现有的测试环境或运行时动态指定的环境中执行。我们甚至让您能够参数化和模块化您的测试,以匹配当今 web 应用程序的复杂本质。一旦测试完成,我们的 orb 将使用测试套件的状态更新您的 CircleCI 工作流,使您可以轻松地隔离故障,并在故障影响您的生产系统之前通知您的团队。
从几行代码开始
CircleCI orbs 只需几行代码就能提供巨大的能力和灵活性。在 orbs 发布之前,一个典型的 CircleCI 配置将包括几十行代码来完成相同的任务。现在有了 orbs,配置就非常简单了。
以下是在 Ghost Inspector 帐户中执行测试套件的示例:
version: 2.1
orbs:
ghostinspector: ghostinspector/test-runner@1.0.0
jobs:
build:
executor: ghostinspector/default
steps:
- ghostinspector/execute-test:
id: $GI_TEST
extra-params: '{"foo": "bar", "other": "var"}'
wait: true
正如您所看到的,我们的配置已经大大减少了,包括为测试套件提供起始 URL 的选项,以及测试步骤所需的附加参数。上面的配置将执行指定的 Ghost Inspector 测试套件,并在继续之前等待结果,如果为 false,则构建失败。
我们还提供了一些更复杂的例子,用于在构建时在 Docker 集群中测试您的应用程序。
包扎
通过 orbs,CircleCI 提高了简化 DevOps 工作流配置的标准。自动化您的 QA 工作并更快地将它们集成到您的构建和部署周期中,这是前所未有的好时机。我们希望 Ghost Inspector 与 CircleCI orbs 的集成将有助于降低测试团队的准入门槛,并减轻端到端测试您的基于 web 的应用程序的负担。
在 2019 年 2 月 6 日上午 11:00 PST/19:00 UTC 举行的网络研讨会“Ghost Inspector 和 CircleCI Orbs:轻松执行您的测试套件”中,了解更多关于 CircleCI 和 Ghost Inspector 的信息。在这里报名。
贾斯汀·克莱姆是 Ghost Inspector 的创始人和技术负责人。他是一名经验丰富的工程师,热衷于创造良好的用户体验。
3 种通过执行构建标准来改进过程的方法
当单独开发软件时,你不必花时间向任何人传达你的决定,而且你很可能像昨天那样格式化你今天的代码。然而,当在共享代码库中工作时,创建和遵循行为标准变得更加重要。对“我们做事的方式”有一个共同的理解,通过消除不必要的来回,混乱的代码审查,以及不得不在不正确的分支上重新做 PRs,最终节省了时间。
然而,新的规则和标准可能难以采用。CircleCI 可以帮助实现过程自动化,并在违反标准时创建内置警报。请继续阅读 CircleCI 帮助您在团队中实施构建标准的三种方式。
1:强制代码格式
当与团队一起开发软件时,确保参与者之间的代码格式一致很重要。
不同开发人员使用的不同风格会导致更困难的代码审查,并增加以后维护软件的复杂性。
有一些文本编辑器插件,甚至 CLI 工具可以用来强制代码格式化,但是它们的成功依赖于开发者是否记得使用它们。CircleCI 可以自动执行代码格式化。为了说明这是如何工作的,没有比 Go (Golang)编程语言更好的例子了。
Go 工具链附带了一个名为go fmt
(一个gofmt
的包装器)的便利命令,它根据社区认可的标准格式化 Go 代码。
在 CircleCI 构建步骤中运行这个命令,加上一点 Bash,可以在代码格式不正确时故意使构建失败。
下面是一个示例.circleci/config.yml
步骤:
#...
- run:
name: "Enforce Go Formatted Code"
command: "! go fmt ./... 2>&1 | read"
#...
出于好奇,下面是正在发生的事情的分类:
go fmt
是检查代码格式并在必要时返回格式正确的代码的命令。./...
是一个特殊的语法,告诉 Go 工具检查这个包(通常是main
)以及在那里找到的任何子包。2>&1
将错误消息重定向到标准输出。对下一步有用。| read
读取标准输出的输出。如果go fmt
发现任何需要纠正的地方或有错误,将输出给read
。read
如果没有得到任何要读取的输出,将返回一个错误。!
这将翻转错误代码。read
有输出时为 0,表示有格式化要做。我们将此反转为失败,因为这意味着开发人员没有格式化他们的代码。相反,当没有输出时,我们希望退出代码为 0;这意味着代码已经格式化并准备好了。
并非所有语言都有代码格式化工具,但幸运的是,第三方工具是存在的。
2:强制实施构建时间限制
对于较大的公司,构建时间是一个关键指标。
跟踪构建时间不仅有助于管理人员跟踪他们的软件管道的效率,还可以暴露构建时间中随机出现的问题。
这些问题可以通过浏览 CircleCI Insights 或第三方仪表板来发现,但是,实际上,这样做的频率有多高呢?
相反,我们可以通过明确地导致构建在超过预先确定的时间量时失败来更直接地暴露这些问题。
例如,如果一个项目似乎有 2 分 10 秒的平均构建时间(使用 CircleCI Insights 可以很容易地确定这一点),我们可以设置一个 5 分钟的硬限制。在两倍于我们平均构建时间的情况下,如果一个构建突然花了超过 5 分钟,我们就让它失败,以便让一个人检查这个构建,看看发生了什么。
这里有一个例子.circleci/config.yml
片段来实现这一点。第一步应该在工作的最开始:
#...
- run:
name: "Set 5m Build Time Limit"
command: sleep 300; touch .fail-build; exit 1
background: true
#...
而第二步应该在最后:
#...
- run:
name: "Enforce Build Time Limit"
command: if [ -f .fail-build ]; then echo "Build ran too long."; exit 1; fi
when: always
#...
第一步,sleep
在我们希望构建失败的时间内在后台进程中运行。在这种情况下,时间是 5 分钟,即 300 秒。如果sleep
命令完成了,这意味着构建仍在运行,因此会创建一个文件.fail-build
。
第二步寻找.fail-build
文件。如果找到了,构建运行得太长了,我们故意返回exit 1
以使构建失败。
如果没有找到,构建时间在 5 分钟以内,我们可以正常退出。
这个技巧对于 PRs 也很有用,在 PRs 中,您希望确保更改不会显著增加构建时间。
3:实施公关目标分支
许多项目都有代码贡献的过程。特别是在开源项目中,通常需要签署 CLA、代码格式化(参见提示 1)以及 PRs 应该基于和/或针对哪个分支的规则。后者在 CircleCI 很容易实施。
时不时地,我会遇到一个项目,在他们的CONTRIBUTING.md
文件中声明,所有的 pr 必须针对develop
分支,而不是master
。下面是一个 CircleCI 配置步骤,它执行了这个规则:
#...
- run:
name: "Enforce PR Target Branch"
command: |
if [[ -n ${CIRCLE_PR_NUMBER} ]]; then
url="https://api.github.com/repos/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME/pulls/$CIRCLE_PR_NUMBER?access_token=$GITHUB_TOKEN"
target_branch=$( curl "$url" | jq '.base.ref' | tr -d '"' )
if [[ $target_branch != "develop" ]]; then
echo "This PR is targeting ${target_branch} instead of 'develop'. Failing build."
exit 1
fi
fi
#...
在本例中,检查$CIRCLE_PR_NUMBER
以查看是否正在构建 PR。如果这是一个 PR,那么使用jq
命令来解析 GitHub API 并确定这个 PR 的目标分支。
然后将新创建的$target_branch
变量与所需的分支字符串进行比较,在本例中为develop
,以确保它们匹配。如果他们不这样做,我们的构建就失败了。
一些注意事项:
- 将“开发”更改为您的目标分支。
- 在这种情况下,需要创建一个 GitHub API 令牌,并将其存储为一个名为
$GITHUB_TOKEN
的私有环境变量。如果这是一个公共项目,请确保将这个 API 令牌的范围明确限定在这个项目上,并且尽可能地减少权限(仅读取权限)。 - 这个例子使用了
jq
命令。该命令预安装在所有 CircleCI 便利映像以及所有 CI 构建(第二方)Docker 映像上。如果你使用的是没有安装jq
的镜像,他们的 GitHub 自述文件提供了说明。
这些绝不是在你的团队中标准化构建的详尽列表。在这篇文章中,我的目的是让你了解什么样的实践是可能的,以及用 CircleCI 自动化这些实践的方法。你的团队实施标准化的一些方法是什么?在讨论或推特上让我知道。
监控团队成功的工程指标| CircleCI
什么是工程度量?
工程度量是团队可以用来做出明智决策并以最大效率运作的数据。一些关于你的软件开发过程的数据,比如已经完成的故事点,已经被证明没什么帮助。在本指南中,我们将描述您可以用来更深入地衡量团队成功的数据。其中包括:
- 管道数据,如跟踪成功/失败率、吞吐量和平均恢复时间
- 团队绩效信息,如信心水平和开发人员满意度
- 使用优化数字,如每个工作或工作流程的信用支出
不要在你的团队中使用 CI?了解为什么持续集成是提高部署频率的关键。
https://www.youtube.com/embed/mzpHV8zuLY8
视频
使用正确的工程指标寻找 DevOps 的成功
找到衡量成功的方法是评估团队交付能力的关键。作为世界上最大的独立 CI 供应商,CircleCI 有一个独特的机会来定量研究软件交付是什么样子的:在成千上万的团队中,通过提交来提交。我们已经看到了团队是如何在实践中构建和部署软件的,在这里,我们将分享使用度量来提高团队绩效的关键。
了解如何用工程团队的四个关键基准来衡量 DevOps 的成功。
跟踪管道数据以做出明智的决策
需要一个地方来跟踪与管道相关的管道数据?使用 CircleCI 的 Insights 仪表盘监控和优化您的 CI/CD 渠道。
使用聚合工作流信息向工程团队展示工作流如何随着时间的推移而执行—跟踪成功/失败率、吞吐量、平均恢复时间以及持续时间指标。跟踪这些指标有助于确保您对管道做出明智的决策。在 CircleCI Insights 仪表板上,您可以:
- 跟踪状态 —查看哪些作业失败,哪些工作流有不稳定的测试。确定管道改进工作的优先顺序。
- 监控持续时间 —找出哪些工作流或作业耗时最长,并找出缓存、并行化和便利映像有助于加快速度的机会。
- 优化消费 —通过洞察每项工作或工作流程的信用支出,优化 CircleCI 上的使用。可预测地计划逐月消费。
下载 2022 年软件交付状态报告,了解最成功的团队如何更好更快地构建软件。
现在您有了一个跟踪您的数据点的地方:您如何改进您团队的工程度量?
我们收集了一些资源,为如何提高团队成功率提供了见解。浏览这些文章,了解与您的团队相关的信息:
工程团队的 KPI:实现速度和质量的持续集成
速度只是故事的一部分。挑战在于知道如何衡量开发团队在速度之外的表现。高速度固然很好,但高信心更重要。这两种品质结合在一起,就形成了所谓的高性能 DevOps。
高绩效团队实际上是什么样子的?与其他 DevOps 团队相比,您如何知道您的团队成员是否做得很好?“快”是什么样子的?在本帖中了解更多关于持续集成对交付周期的影响。
为您的团队设定 DevOps 成功基准
虽然没有每个团队都应该追求的普遍标准,但是团队可以使用合理的度量标准作为目标。最终,你测量基线并逐步改进这些指标的能力比追求“理想”数字更有价值。
借助我们的 2022 年数据报告,了解您的团队如何符合行业工程标准
阅读我们的 2022 年软件交付状态报告,了解我们从全球软件、医疗保健、零售、金融、房地产和媒体等领域的 50,000 多个组织中收集到的关于构建优秀软件开发团队的最佳实践。
入职远程员工的基本清单- CircleCI
原文:https://circleci.com/blog/essential-checklists-for-onboarding-remote-employees/
入职是一个很难做好的过程,对新员工和团队都是如此。对于新人来说,感觉自己需要迎头赶上并尽早证明自己的价值并不罕见。对于团队来说,这对每个人的生产力都是一个打击,一个新的人需要弄清楚如何与他一起工作,以及为什么团队以这种方式工作的问题。
远程入职可以让这些问题以全新的角度暴露出来,尤其是在没有“社交赠品”来支持归属感的情况下,比如在去开会的路上撞到某人,注意到队友桌子上的一个很酷的小摆设,或者在午餐桌上碰到一个同事。所有这些都是社交活动,为新员工和现有员工提供了打破僵局的借口,并以一种轻量级的方式感觉自己是团队的一部分。
当你远程工作时,你只能通过镜头看到“办公室”,而且视野非常狭窄。在专注于完成工作的常规团队会议上,团队成员只能看到彼此或彼此交谈,这种情况并不少见。这对新员工来说是孤立的,让团队感觉更像是一群贡献者,而不是一个为目标而努力的团队。
随着远程工作越来越普遍,加入远程团队变得越来越重要。我想分享一下我的团队在过去 6 个月中有效地让远程员工入职所学到的东西,以及我们如何解决前进道路上的常见障碍。
在我们的工程组织中,我们在两个文档中记录了我们的新入职体验:我们的入职期望和我们的工程师入职清单。通过这两个文档,您将学会设计一个灵活且适应性强的入职流程:每个人的学习方式不同,或者对如何开始有自己的偏好。我们以此为指导,确保我们的团队处于最佳位置,在新员工过渡到他们的团队或组织时为他们提供支持。
员工入职:期望
入职期望为构建成功的远程入职的两个重要组成部分奠定了基础:沟通的开放性和主动拓展。他们一起在一个远程团队中获得了一些缺失的社交赠品,并创造了一个友好的环境。我相信这些是你能为新员工和你目前的团队做的最重要的事情,并且几乎不增加管理费用。我们来说说为什么:
在办公室里,我们只需走到最适合回答我们问题的人面前,然后直接提问。你的团队可能会注意到并听到一些对话,并最终感到与正在发生的事情有关联。远程模拟将发送私人/直接信息,这无意中隐藏了通信,即使这不是意图,导致团队周围发生的事情脱节。我们竭尽全力,通过更多地依靠在团队渠道中交谈,并标记我们希望看到消息的人,来恢复这种开放性。这有助于让团队成员感觉像一个整体,而不是一群个体。
主动外联。在一个陌生的地方,很难接触到不认识的人。你可以考虑去一个新的城镇旅行并问路。你可能不知道习俗、语言或任何真正的东西,这会让人觉得你要求很多。如果当地人问你是否需要帮助,会告诉你他们愿意花时间帮助你适应新的环境。当加入一个全是陌生人的新团队,或者一家有全新公司文化要应对的新公司时,情况也是如此。当现有成员伸出援手时,它消除了闯入一个新地方的压力和焦虑,并发出了一个明确的信息,即他们在这里并愿意提供帮助。谁不想要一个兴奋地带你四处逛逛的导游呢?
参见入职期望大纲(提示:制作一份副本用于您的团队)。
入职工程师:远程员工清单
我们的第二个文档是工程师入职清单,在新员工入职体验期间为他们提供指导。我们不期望任何人严格遵守,而是用它来告知他们应该询问什么或与他们的入职伙伴合作什么。给出的时间表是为了给出一个新员工应该何时进入下一组主题的大致想法,而不是一个截止日期。每个人都有自己的节奏,确保人们有效参与并不是一场比赛。
阅读工程师入职清单(提示:复制一份供您的团队使用)。
为远程员工创造良好的入职体验
我们希望通过这篇文章来引发一场对话,讨论我们如何让远程招聘对每个人来说都是一种更舒适的体验。因此,请随意使用我们的流程作为您自己的流程,或者根据您的需求进行定制。我们计划分享我们如何改进它,并希望听到您的意见,我们可以如何共同改进它!
PS:我们在 CircleCI 招聘了很多人。如果您有兴趣帮助我们改进入职、招聘或只是发展 CI/CD,请查看我们的职业页面。
2021 年 DevOps 基本原则| CircleCI
DevOps 成功工程团队的原则和实践
欢迎阅读 CircleCI 指南,了解领导高绩效开发团队的基本原则。在本指南中,您将找到相关资源来帮助您的团队培养 DevOps 文化,从而做出明智的决策并最大限度地提高运营效率。
许多团队现在正在转向 DevOps,这是有充分理由的:使用 DevOps 实践有助于团队更好地响应市场变化。他们可以更快、更安全地部署代码,更不用担心中断生产。
但是切换到 DevOps 并不是一个非此即彼的命题。是的,DevOps 是一种将运营知识带入开发的思维模式,但它也提供了一整套流程、方法和使用工具的方式,使其与众不同。
在购买所有工具之前,培养一个 DevOps 团队环境
DevOps 是一系列问题解决过程中的最新一个,每个过程都带有一个充满工具的数字车库:CI/CD 系统、测试框架、监控工具和安全审计工具等等。但是在采用工具之前应用 DevOps 思维模式是必要的。
在转移到 DevOps 之前,确保您的团队在以下方面保持一致:
- 每个人都在同一页上关于您试图通过这种转变实现的目标。每个人都应该在你试图解决的问题上达成一致,并且在痛点上保持一致。
- 从小处着手。不要试图一夜之间把整个组织打造成一个模范 DevOps 团队。相反,从一个团队开始,看看流程改变在你的组织中是否有效。
- 经常测量。在您开始任何改进计划之前,获取您当前所处位置的准确指标(即我们的开发周期需要 X 时间)。一旦你实施了改变,你就可以衡量它们的有效性。
- 不要试图一次自动化所有的事情。关于开发运维的一个误解是,所有基础架构配置和配置管理都必须自动完成。这被称为“基础设施,代码为 (IaC)。”IaC 实践旨在支持大规模应用。在自动化复杂的部署场景之前,尝试自动化应用程序的构建和测试。
有关 DevOps 文化和工具的更多信息,请参见:转移到 DevOps:您真正需要什么工具?或下载devo PS 文化的基石电子书。
关于代码形式的基础设施的更多信息,请参见:我如何使用基础设施作为代码?
获得管理层对开发运维的认可
让您的经理对新的 DevOps 工具说“是”可能是一项挑战。使用以下提示来获得新工具的批准:
- 强调问题,而不是工具。在任何对话开始之前,我们需要确定行动项目。没有哪个经理希望召开没有可操作性见解的会议。
- 使用相关数据来支持你的需求。开发人员是生成数据的专家,所以在你的提问中包含一些具体的统计数据。
- 从你团队中最不可能的粉丝那里获得认同。重要的是,要让那些将受到影响的人和那些可能对新工具有意见的人参与进来。
- 演示工具并邀请提问。询问您的团队是否看到引入该工具可能会带来的任何问题。
欲知更多关于接近管理层的信息和建议,请阅读:让你的经理对 DevOps 工具说“是”。
使用 DevOps 提高安全性
CI/CD 管道是您的技术堆栈的一个关键部分,您的基础架构可以访问许多不同的资源,从开发和生产环境到分析密钥和代码签名证书。您的管道可以访问的资源越多(安全机密、专有代码、数据库等。),保持 CI/CD 系统的安全就越重要。
如何利用 DevSecOps 保护 CI/CD 管道?我们建议实施以下三种解决方案中的安全最佳实践:
- 安全管道配置 -可以使用您的 CI/CD 管道配置来降低发生安全问题的可能性。(查看 CircleCI orbs )。
- 代码和 Git 历史分析——花时间识别已经提交到代码库中的秘密,以便您可以停用和替换它们。
- 安全策略实施——某些安全方面无法基于已知漏洞进行静态检查,而是特定于您的特定公司,因此需要作为策略进行编码。
要了解关于采用 DevSecOps 方法的更多信息,请下载本电子书,CI/CD 安全和 DevSecOps 终极指南。
为你的团队设定有意义的开发目标
当谈到团队成功时,找到正确的 DevOps 指标来衡量是至关重要的。虽然没有每个团队都应该向往的通用标准,但我们的数据和我们在我们的平台上看到的 2020 年 DevOps 软件趋势表明,团队有合理的基准来设定目标。
最终,你测量基线并对这些指标进行增量改进的能力比追求“理想”更有价值。
下载 2020 年软件交付状态:面向工程团队的数据支持基准了解您和您的团队如何在未来扩大您的软件交付。在这里下载的报道。
每个声音都很重要:我在 CircleCI 实习的时间
原文:https://circleci.com/blog/every-voice-counts-my-time-as-a-circleci-intern/
这篇文章由雅克·加西亚撰写,她是 CircleCI 的 2017 年夏季工程实习生。
你好 CS
作为一个从没听说过“编码”的来自加州康普顿的孩子,如果有人在 4 年前告诉我,我将主修计算机科学,我会给他们怀疑的目光。
我来自加利福尼亚的康普顿(是的,“直接离开”康普顿,不,我没有看过这部电影),目前我正在加州大学伯克利分校攻读学士学位。在意识到我当时的专业化学工程并没有(也不会)让我开心之后,我在大一的时候没有申报。有东西不见了。我想加入 STEM,解决问题,并以积极的方式影响他人。我希望能够思考我所建造的东西的社会意义,并尽可能快地影响尽可能多的人。感觉很失落,我研究如何将我对社会公益和 STEM 的热情结合起来。我找到了各种关于创业公司的文章,并熟悉了这个概念。具体来说,我遇到了 Code the Change ,这是一个致力于利用他们的技能进行社会变革的非营利组织。我给首席执行官萨姆·金发了电子邮件,询问他在计算机科学方面的经验以及他能给我的任何建议。在与他交谈后,我决定我要开发有用的软件,并希望能影响我们生活、交流、思考、构建等的方式。以一种积极而有意义的方式。
我去切尔莱西的路
去年,我决定申请加入由劳拉·魏德曼·鲍尔斯和特里斯坦·沃克共同创办的非营利组织 Code2040 。他们的使命是到 2040 年结束科技领域缺乏多样性的状况。我立即与他们的使命联系起来,并相信这将是一个特殊而安全的空间,让我成为一名色彩工程师。我是 1300 多名申请人之一,350 名入围者,并成为 2017 年 135 名 Code2040 研究员之一。两家大公司给了我两份实习机会,最终我决定接受 CircleCI 的邀请。CircleCI 的使命是帮助其他公司更有效地构建有意义和强大的软件,所以这似乎是我最适合的组织。
在接受我的邀请之前,CircleCI 的招聘经理 Jen Hugo 邀请我参观位于美丽的旧金山的总部。她帮我联系了之前的 Code2040 研究员安德烈斯·库沃(Andres Cuervo),他将在实习结束后以全职员工的身份回来。当我坐下来与安德烈斯交谈时,他问我想从实习经历中得到什么。谈了一会儿工作后,我觉得很舒服,可以告诉他我第一次实习的恐惧。我告诉他我多么害怕自己不够聪明,不够“好”。他承认我的恐惧,并告诉我他也有同样的恐惧。他告诉我,他喜欢 CircleCI 的透明性,学习的空间,以及每个人都愿意合作并帮助彼此成功。与安德烈斯交谈真的让我觉得 CircleCI 的环境不仅仅是建筑;学习和合作同样重要。这对我极其重要。我不习惯在工程文化中感觉如此舒适,这不仅仅是因为在我的 CS 系里很少有人长得像我。我不习惯被提供空间只是问问题,探索和学习,我可以告诉 CircleCI 真的相信创造这样一个空间。了解 CircleCI 的文化最终让我接受了他们的提议,而不是我的其他提议。
定制的学习环境
在开始实习之前,Justin Cowperthwaite,开发人员、团队负责人,也是我在 CircleCI 未来的经理,找到我,告诉我我想从实习经历中获得什么,并欢迎我加入我的新团队:团队成长(也称为“团队资金”)。在加入之前,我几乎没有前端开发的经验。当我暗示对后端感兴趣时,他给了我探索前端和后端开发的机会。听到我将有多少自由,我很兴奋。贾斯汀与 Team Money 的产品经理 Rishi Kumar 密切合作,为我提供了一个实习机会,让我尽可能多地接触和体验。Rishi 帮助我成长为一名工程师,他用各种项目挑战我,为前端、后端、营销和其他团队解决问题。他们两个让我在 CircleCI 的经历成为我所希望的一切。
会见团队
第一天,我见到了团队的其他成员:汉娜·亨德森、大卫·戈克和菲尔·哈格伯格。汉娜是我实习期间的导师。我非常钦佩她的职业道德和毅力。她的效率和工作质量经常受到同事和项目经理的称赞。尽管在 CircleCI 工作不到一年,她已经赢得了团队的尊重和信任,被认为是一个只会做事,没有借口的人。换句话说,她踢屁股。除了是一名熟练的工程师,Hannah 总是给我诚实的反馈和支持。她让我觉得自己参与了讨论和会议,并对我在项目合作中所做的贡献给予了肯定。我觉得她理解我对成为科技公司一员的所有疑虑和问题。她没有牵手我,但她也没有让我一个人飘着。在 CircleCI 的这段时间里,我能够这么快地学到这么多东西,这要归功于她的指导和耐心。尽管我不得不学习一门新的编程语言 Clojure,而且以前从未接触过或见过前端开发的任何东西,但我能够在开始的同一周开始构建和编码。她的支持让我如释重负,尤其是因为我真的不知道在科技公司工作会是什么样子。尽管来自不同的背景,我还是和她有关系。作为一个在男性主导领域的女性,她理解我的观点、不安全感和恐惧。
我的经理贾斯汀·郭伯伟(Justin Cowperthwaite)不仅才华横溢,而且聪明风趣(我很快了解到,这是 CircleCI 非常常见的特质)。他的奉献精神、职业道德和领导力很快给我留下了深刻的印象并激励了我。尽管在 CircleCI 工作了不到两年,并以初级工程师的身份开始了他的职业生涯,但他已经迅速晋升到团队领导和管理职位。今年,他开始管理与 Code2040 的合作关系,致力于让科技行业更加欢迎来自各种背景、种族、性别和性取向的所有人。通过我们每周 1-1 的会议,我觉得他真的很关心我在 CircleCI 的利益和福祉,结果,我真的成长为一名工程师。在我们一对一的会面中,他开诚布公地谈论了各种话题,包括:时间管理、个人理财、如何在公司留下自己的印记,以及许多其他话题。他总是有非常好的建议,从要读的书(“The Lean Startup”作者 Eric Ries),到如何从我的职位和我将来可能担任的任何职位中获得最大收益(即超越并在需要的地方提供支持,即使它“超出”我的工作描述),到如何编写优秀而高效的代码(哦,亲爱的抽象,我们如何认为你是理所当然的……)。
每个团队成员都很重要
我有幸与 David Goeke 和 Phil Hagelberg 搭档工作,他们都是高级后端工程师。他们非常有耐心,通过征求我的反馈和意见,让我觉得自己也参与到了他们的建设中。在我和大卫的结对过程中,我欣赏他包容的语言:他总是用“我们”来表达事情。虽然很微妙,但它确实对我产生了影响。他会问我如何处理我们正在做的事情,如何测试我们的代码,他会给我提问的空间。我和菲尔的经历非常相似,我认为这是 CircleCI 独特文化的真实写照。
CircleCI 有一种工程师文化,他们真正关心他们在建造什么,他们如何建造,以及他们的影响。我这么说是因为他们非常重视用户体验以及他们对用户反馈的回应方式。该团队的结构支持通过结对(无论是通过面对面还是视频通话)、专门会议和 1 对 1 的方式进行学习和协作。尽管我只是一名实习生,但他们确实让每个工程师的声音都很重要,甚至包括我自己的声音。我不断被提醒要问问题,当我需要支持时,随时向任何人伸出援手。我非常自豪和感激成为 CircleCI 工程师团队的一员。CircleCI 的文化确实很特别,它帮助我了解了在我作为一名工程师的职业生涯中,我想和什么样的人一起工作。
探索领域驱动的设计
原文:https://circleci.com/blog/exploring-domain-driven-design-at-circleci/
DDD 如何促成更有成效的对话和更干净的代码
我在 CircleCI 的团队专注于计划和支付,随着我们的成长,他们在过去一年经历了许多组织变革。帮助我们在这些变化中保持一致性的一件事是采用不同的方法来编写软件:领域驱动设计,也称为 DDD。
简洁地定义领域驱动设计是困难的,但是简短的回答是,它是一种通过使用普遍接受的模型来连接软件架构和相关领域的方法。换句话说,软件匹配域。有许多可用的资源来定义 DDD 并深入细节,但对我的团队来说,有两个概念对我们非常有帮助:定义我们的有界上下文和我们无处不在的语言。
有界语境与无处不在的语言
如您所知,有界上下文是一个域的离散片段,具有清晰的边界。有界上下文可以包含一个或多个域,这些域可以有嵌套的域,称为子域。有界上下文的集合被称为上下文映射。最后,所有的上下文都有相应的无处不在的语言:上下文中明确定义的术语的集合。团队的所有成员都应该使用这些术语,并且在代码中也应该有适当的表示。例如,在计划和支付上下文中,“用户”是触发作业的任何人或任何事物,但是在 CircleCI 的其他几个上下文中,“用户”实际上是客户的同义词。希望您已经想到了,但是“用户”实际上并不是一个包含在无处不在的语言中的好术语。它是模糊的和不精确的。但是你可以想象,一旦使用了这样的术语,就很难摆脱了。这就是为什么如果可能的话,你应该从一开始就考虑无处不在的语言。
计划和支付团队的环境图示例
这两个概念都很重要,因为它们确保团队的所有成员都在谈论同样的事情。通过消除歧义,无处不在的语言允许更有意义的讨论。有界上下文努力给我们一个清晰的画面,告诉我们代码驻留在哪里,我们的努力应该集中在哪里。在我们的团队中,这两种方法都达到了预期的效果。
对我们团队的好处
我的团队中有许多问题通过实施 DDD 得到了极大的改善。首先:随着时间的推移,我们已经对触发构建的人或事物有了许多定义:“参与者”、“活跃用户”、“用户”等等。而且不止一次,这给我们讨论这个特性的时候造成了困惑。我们是在谈论提交作者吗?我们说的是 Github 公关负责人吗?我们是在谈论触发构建的机器人吗?最糟糕的是,如果我们感到困惑,那么我们的客户还有什么机会呢?我们的代码有多少机会是正确的?
令人惊讶的是,我们发现用户实体的定义对我们来说并不重要,因为它与我们的上下文无关。事实上,我们需要了解的是,当一个客户开始构建时,我们只需要计算唯一的客户,这样我们就可以跟踪他们使用的座位数量。定义我们无处不在的语言简化了命名变量、创建吉拉门票、编写文档和入职的过程,因为所有术语都被团队简化和接受。
建立我们的有界上下文也有很多好处。将我们的代码尽可能地移近产品已经消除了与决定代码应该存在于何处相关的许多困难。此外,因为我们是作为一个团队来决定我们的上下文的,所以在技术决策上达成共识通常是微不足道的。最重要的是,我们现在有了一个关于我们的代码实际上是如何编写的概念模型,这使我们能够积极地参与和参与领域讨论和决策,从架构到定义我们的产品路线图。
给 DDD 一个机会
我不能代表其他人的经历,但是尽管我对 DDD 只有粗略的了解,我绝对能感受到我的团队在生产力上的不同。作为交换,我们所要做的就是花一周的时间在便利贴和白板的海洋中痛苦和磕磕绊绊。我们还有很长的路要走,但幸运的是,有了 DDD,没有什么是永恒不变的,我们的定义可以随着我们的领域而发展。说真的,如果你还没有,我强烈建议你花点时间,深入研究,整理你的领域。代码和产品之间的内聚性是值得的。
更多资源
【视频】CircleCI CTO Rob Zuber 谈无处不在的语言和吞吐量
反馈循环:改善平均恢复时间的关键
原文:https://circleci.com/blog/feedback-loops-the-key-to-improving-mean-time-to-recovery/
红色构建是 DevOps 团队生活中的一个事实:如果你用自动化工具开发测试良好的软件,你的一些构建将不可避免地失败。但是从失败的构建中缓慢的恢复时间不应该被认为是理所当然的,因为它们损害了团队加速开发周期的能力。为了缩短平均恢复时间(MTTR),开发人员需要数据来解决问题。持续集成和持续交付(CI/CD)通过快速提供关于您的构建的数据,创建开发运维团队所需的快速反馈循环,有助于缩短恢复服务所需的时间。
我们很快会说,速度从来不是健壮的 DevOps 实践的唯一目标。正如我们在最近的报告中所解释的那样,CI 的数据驱动案例:实践中 3000 万个工作流揭示了关于 DevOps 的什么,像 MTTR 这样的指标需要与其他质量指标(如交付时间和部署频率)一起理解;还有,速度需要和质量相匹配。CI/CD 有助于加速开发,同时还为开发运维流程增加了智能和洞察力。交付的一致性是自动化的无名英雄:没有可靠、一致质量的速度是没有帮助的。
本文是系列文章的第三篇,我们将探讨 CircleCI 工作流中的数据如何支持 MTTR 等行业标准指标。这些指标表明,在不牺牲速度的情况下优化稳定性是可能的,CircleCI 的数据显示了团队在现实生活中如何根据这些指标进行操作。
在更短的时间内将构件从红色变为绿色
缩短平均恢复时间要求您快速获得可操作的信息。如果您的团队可以快速返回失败状态,他们可以在最短的时间内将构建从红色变为绿色。采用 CI/CD 实践能够实现快速反馈循环,并且是确保开发人员快速获得信号的最佳方式。通过强大的 CI/CD 实践,开发人员可以从您的测试套件中访问实时工件,例如日志和覆盖率报告,这使开发人员有机会在与生产环境相当的环境中进行故障排除。
为了了解观察到的开发行为如何与行业标准进行比较,我们查看了 2019 年 6 月 1 日至 8 月 30 日期间观察到的超过 3000 万个工作流的 CircleCI 数据。工作流代表:
- 每天运行 160 万个作业
- 超过 40,000 个组织
- 超过 150,000 个项目
以下是我们的发现:
- 记录的最短恢复时间不到一秒。
- 最长时间为 30 天。
- 平均恢复时间为 17.5 小时。
只有当两个工作流几乎同时启动,并且一个失败而另一个通过时,最短恢复时间少于一秒的情况才会发生。在任何其他情况下,都不可能在那么长的时间内收到信号并做出响应。
对于 30 天的最大记录 MTTR,这是 CircleCI 的数据集在 30 天标记处截止恢复的一个函数,并不意味着在 30 天内会发生恢复。
这里有趣的数据不是最短时间或最长时间,而是恢复的中值时间,即 17.5 小时——大约是一个工作日结束和另一个工作日开始之间的时间长度。这意味着当工程师在一天结束时收到一个失败的信号,他们会等到第二天来解决它,并可能提供对 DevOps 团队如何运作的洞察。
从我们的数据中有什么收获?
17.5 小时的中值与民意测验和调查反映的传统观点相反,民意测验和调查表明 MTTR 要快得多。是什么导致了报告行为和观察行为之间的差异?我们猜测,调查设计本身正在影响一个快速报道的 MTTR。
关于工程指标的调查问题通常是这样措辞的:“对于您工作的主要应用程序或服务,请告诉我 _____?”然而,CircleCI 的数据涵盖了所有分支的所有工作流,而不仅仅是默认分支,也不仅仅是主应用程序。虽然观察到的中值恢复时间为 17.5 小时,但主应用程序默认分支的平均恢复时间可能更快,更像是几分钟而不是几小时。
根据我们的工作流数据,在 90 天的观察时间内,超过 30%的活动项目分支从未失败过(即,100%绿色)——这意味着 MTTR 为 0 秒。因为他们从来没有失败过,所以他们从来不需要恢复。
我们工作流中其他有趣的数据点显示,50%的恢复发生在不到一小时的时间内,25%的组织在不到 15 分钟的时间内恢复。我们还注意到,50%的组织在一次尝试中恢复,75%的组织在两次尝试中恢复。
表现最好的 10%的人花了不到 10 分钟的时间做必要的工作来修复他们的构建并回到绿色。这支持了 DevOps 2019 报告的状态中发现的精英执行者的恢复时间指标。报告指出,精英团队的平均恢复时间不到 1 小时,而表现不佳的团队恢复时间在一周到一个月之间。
有趣的是,在三个小时和 17.5 小时的中间时间之间的数据有很大的频率差距,这表明如果红色构建没有在三个小时内恢复,它很可能要到第二天才能修复。
每一点 CI 都有帮助
改善 MTTR 是成为高绩效 DevOps 组织的一步。而且,正如我们在 CircleCI 坚信的那样,即使是一点点也有助于提高性能。即使你刚刚开始 CI/CD,并且做得不完美,你仍然在正确的轨道上。
在这个四部分系列的下一篇也是最后一篇文章中,我们将关注变更失败率。如果你错过了前两篇文章,请阅读关于交付周期和部署频率的文章。
你应该知道的 5 个有用的 CircleCI 特性
原文:https://circleci.com/blog/five-secret-circleci-features-you-should-use/
来自出版商的说明:您已经找到了我们的一些旧内容,这些内容可能已经过时和/或不正确。尝试在我们的文档或博客中搜索最新信息。
近两年来,我们的支持和客户成功团队一直在帮助用户充分利用 CircleCI 平台。在那段时间里,我们已经看到许多用户与同样的障碍做斗争,其中大多数可以通过鲜为人知的救生功能来解决。以下是 CircleCI 的 5 大功能,可以帮助您节省时间,提高控制力,更快地回到绿色。
自动取消 GitHub 上的冗余构建
什么是:当一个新的构建在同一个分支上被触发时,自动取消该分支上任何排队的或者正在运行的构建(除了您的默认分支)。
为什么需要它:如果你已经改进了一个构建,为什么还要等它完成呢?使用此功能自动跳过冗余的构建,并为最新的构建节省带宽。注意:这个特性只适用于由推送至 GitHub 触发的构建。
如何获取:要启用此功能,您可以导航到项目的“高级设置”并启用“自动取消冗余构建”选项。
仅 PR 构建功能
它是什么:仅在请求打开时运行构建。
为什么需要它:通过仅在提交拉请求时构建,您消除了每次修改分支时的构建。这可以让用户更好地管理他们的队列。
如何获取:要启用此功能,您可以导航到项目的“高级设置”并启用“仅构建拉取请求”选项。
平行
什么是:跨多个容器自动分割和平衡测试,以减少您的总体构建时间。有关我们如何自动平衡您的测试的更多信息,请参见这里。
为什么需要它:并行性加快了测试和构建运行时间,让您获得更快的反馈。
如何获得:登录 CircleCI。在你的仪表板上,你会发现一个当前在 CircleCI 上构建的所有项目的列表。单击您想要并行化的项目旁边的齿轮图标,然后单击“调整并行度”在那里,您可以选择要用于该回购的并行容器的数量。对你的其他回购重复这个过程。您的每个 repos 都可以设置为不同的并行级别,以实现最大程度的优化。
其他仅限管理员的权限
什么是:禁止非管理员修改关键项目设置。
为什么需要它 : CircleCI 镜像 GitHub 的权限,只允许管理员对你的订阅、信用卡信息等进行重要更改。更进一步,您可以确保只有应该更改项目设置(如并行度、执行环境和 envars)的帐户才有权这样做。注意:此功能可应用于组织或项目级别,并且不会阻止用户使用以下功能:通过 ssh 调试、重建、使用 ssh 重建、无缓存重建。
如何获得:在应用程序中创建一个支持请求,并请求管理员专用的项目设置权限。确保包括(区分大小写的)组织名称或要启用的回购列表。
SSH 进入运行构建
它是什么:您的容器可以持续 30 分钟,同时您可以安全地排除异常情况。
为什么需要它 : SSH 到正在运行的构建中,查看日志文件、正在运行的进程等等,以便更快地排除故障。
如何获取:要为正在运行的构建启用 SSH 访问,请转到“通过 SSH 调试”选项卡,然后单击“为此构建启用 SSH”按钮。查看这里的了解更多细节或者在新版本上启用 SSH。
额外收获:为什么“捆绑安装”会失败?
最近几周,几个 CircleCI 用户已经注意到bundle install
在他们的构建上失败了。这通常是由于Bundler 1 . 14 . 0(1 月 20 日发布)自动升级,除非你锁定以前的版本。Bundler 1.14 . x 版本坏了。我们建议您在运行“bundle install”之前安装 Bundler (1.13.x)的稳定版本,以避免失败。
福布斯将 CircleCI 评为美国最佳创业雇主
原文:https://circleci.com/blog/forbes-names-circleci-to-america-s-best-startup-employers-list/
在过去的一年里,我们在 CircleCI 的团队一直在努力工作。从推出像 CircleCI Insights 和 private orbs 这样的主要产品添加,以及像我们的开发者中心和软件交付状态报告这样的教育资源,其中包括针对高性能工程团队的第一批 CI/CD 基准,似乎每天都有新的东西值得期待。
所有这些都发生在对全球每个人来说前所未有的时代。因此,我们加倍了员工福利,以确保我们的员工感到舒适和安全,能够最好地工作——更多假期、冥想应用和专业学习订阅、送餐津贴,以及投资于我们团队的培训和发展。
其他人也注意到了这项工作。
我很荣幸地告诉大家,CircleCI 已经被福布斯评为 2021 年美国最佳创业雇主。
福布斯与市场研究公司 Statista 合作,在其第二次年度美国最佳创业雇主排名中,确定了员工最喜欢的新兴公司。这份榜单是根据三个标准对 2500 家拥有至少 50 名员工的美国企业进行评估而编制的:雇主声誉、员工满意度和增长(欲知完整情况和方法,点击此处)。
被认可总是一种肯定。这份清单很特别,因为它深深地影响了员工的体验。我们以不同的方式做事,尤其是在这三个对我们的使命和价值观至关重要的领域。
支持健康的混合劳动力
我们的团队在三个主要地区合作:亚太、欧洲和北美。作为人类,我们努力与一个更大的目标联系在一起,但我们也想感觉与周围的人联系在一起。当我们在视频通话中以像素的形式或在聊天应用程序中以图标的形式与人互动时,我们很容易忘记屏幕的另一端也有人。当您的组织处于高速增长模式时尤其如此。
几年前,CircleCI 的工程团队逐年增加一倍,并变得更加全球化。相反,管理团队小得令人难以置信。在所有这些增长之后,我们在发展我们的工程文化方面遇到了挑战。我们的知识非常孤立,我们需要找到一条前进的道路,让我们能够扩展业务。
因此,我们创建了一个工程能力矩阵,它融入了我们所做的一切。从招聘到结构化反馈,再到绩效评估,它帮助我们让每个人都遵循相同的标准,并在我们扩展时明确预期。
点击此处查看 CircleCI 团队成员关于入职最佳实践的其他有用资源:
合作
我们的协作流程和工具使每个人都能访问他们工作所需的信息和资源,做出明智的决策,不受时区的限制。
正因为如此,我们将不同的背景、经历、沟通风格和协作偏好,以及更多的差异带到了(虚拟)桌面上。通过渗透,或在字面上的水冷却器,很少发生有机的事情,但同时,当我们分布在不同的地点和时区时,所有团队面临的许多沟通困难都加剧了。
我们找到了应对这些挑战的五种方法:
-
建立信任。建立结构的第一步是建立关系。例如,在 CircleCI,我们建立了定期结对编程轮换和工程讲座等结构,以帮助我们的分布式团队建立联系。
-
围绕合作方式构建。随着我们工程部门的扩大,我们已经转向更简化的工程交付流程。但是每个团队决定如何实现日常流程,如每日站立会议、计划会议或协作。每个团队都有特定的需求,他们知道如何最好地满足这些需求。
-
移除拦截器。我们都知道被卡住有多沮丧。建立途径——例如,投资自助信息访问、跨团队相互支持以及建立知识共享——可以帮助事情向前发展。
-
持续改进。利用回顾来讨论和改进团队合作的方式。无可指责的事后分析也是帮助理解问题和推动解决方案的重要工具。代码审查、指导和知识共享可以帮助团队成员相互学习。你如何谈论学习——尤其是你讨论错误的方式——很重要。这些决定将从根本上塑造你的团队文化,并决定人们在他们的核心需求中是感到安全还是受到威胁。
-
向直线行驶。向你的团队传达战略、方向和相关的战术细节——记住,过多地传达这些细节几乎是不可能的。总是重复重要的事情。
以下是我们的员工对在家工作的一些最佳解读:
将人们聚集在一起
我们的团队定期进行虚拟会面,面对面地相互了解、建立关系、同步、协作和制定战略。
这些都是个人主导的活动,如每周的填字游戏,指导瑜伽和冥想课程,虚拟快乐时光和各种团队建设活动,如“带一只美洲驼到你的会议”和“团队 Quiplash”
此外,CircleCI 还赞助了四个员工资源小组(ERGs),目前包括 CircleSHEi、Queersphere、Onyx 和 Circle Minds。这些小组定期会面,讨论每个小组的个人需求、需要到位的公司政策和福利,以及公司可以做些什么来更好地满足他们的需求。
“CircleCI 确实是一个工作的好地方。我们有强大的产品,很好的工作/生活平衡,以及推动和支持我们的优质团队成员,”–高级解决方案工程师 Vinny Thanh(本月庆祝他在 CircleCI 的第二年)
想要帮助创新组织今天就交付明天的软件吗?加入我们的团队
从代码牛仔到基础架构架构师:作为开发人员我希望知道的 5 件事
原文:https://circleci.com/blog/from-code-cowboy-to-infrastructure-architect/
来自出版商的说明:您已经找到了我们的一些旧内容,这些内容可能已经过时和/或不正确。尝试在我们的文档或博客中搜索最新信息。
作为开发人员,我希望知道的 5 件事
理解如何编写一个应用程序和理解在它下面工作的基础设施是有区别的。今年,当我从一名开发人员转型为一名 SRE(站点可靠性工程师)时,我看到了分布式系统在一家真实的公司中是如何工作的,这确实改变了我对编写代码的看法。
当你专门做软件开发时,你不会考虑它将如何被支撑。当我部署我的第一个网站时,我不知道该怎么做。我不太在乎写测试。让我们现实一点:我只关心添加新功能和看到最终产品。我不知道如何托管静态图像,也不知道如何配置服务器。
以下是我希望在从事开发工作时能够更加关注的一些事情:
1。编写准确的提交消息&清晰的文档
确保你的代码是有效的,并且在你上传之前被评论过。清晰的提交消息使得人们在你的代码评审过程中更容易理解你在做什么,并且在某些东西没有通过的时候帮助调试过程。我一个文件一个文件地写我的提交消息;这给了代码审查者一个机会来审查我添加了什么以及我为什么添加它。以前,我只是想跑得快一点,但现在我意识到第一次就把它做好可以节省更多的时间。当这些东西上传到 GitHub 上,而你没有清楚地写下你做了什么时,它会导致一个糟糕的审查会议和需要更长时间来解决的问题。
2。编写重点测试
我曾经看过一条推特,上面写着“你最喜欢的公司离完全关闭还有 30 分钟”。对我来说,这意味着我们喜欢的公司并不像我们认为的那样坚不可摧。保持他们的运转需要很多努力和团队合作;经营一家公司很难。你开始意识到在基础设施层面,事情会变得多么糟糕。防止这种情况的一个方法是编写好的测试。你的测试应该是确定性的,清晰易读的。如果你很好地测试了你的东西,你将会防止由于改变代码或者更大的事件而导致的退化。
3。确保我的代码安全
我学到了很多安全方面的知识,这让我更加了解代码的生命周期。任何时候你把东西放到互联网上,代码完整性变得非常重要。您不仅可能将您的客户置于风险之中,还可能将您公司的信息置于风险之中。当人们使用你的应用程序时,他们相信隐私和他们的信息在你的应用程序中是安全的。如果没有适当的安全措施,您就不会赢得客户的信任。在 Equifax 事件及其广泛影响之后,我意识到在处理大型代码库时将安全性放在首位是多么重要。所有好的设计都考虑到了安全性,无论是设计抗震的房子还是创建强大的软件——好的设计意味着在代码的每个部分都将安全性放在首位。
4。时间管理
作为一名 SRE,随叫随到迫使我提高了自己的时间管理技能。它也极大地改善了我的生活。我总是想一次做很多事情,但我知道当我随叫随到时,我所有的注意力都是为了保持网站和一切顺利运行。所以管理我的时间来做我的工作项目比以往任何时候都重要。现在我使用 Evernote 这样的新工具来组织我的想法,并使用任务列表来确保我的任务完成。我列出一周的任务清单:这就是我如何进入工作周的最佳状态。在我的一天中,我把任务划掉,如果我没有完成它们,我会把它们添加到第二天的页面上。我更有条理地完成我的项目,这样当我值班时,我可以跟踪我前一天没有完成的事情,这意味着我可以平衡我的值班和我的开发项目。
5。被关注
我已经认识到在我值班期间保持清晰注意力的重要性,因为我总是必须集中精力并随时准备做出反应。如果我的任务是维护我们产品的基础设施和安全性,我就不会被其他事情分心。万一出了问题,我的团队就指望我了。我的反应能力很重要,因为如果我能阻止事件升级,就能帮助升级级别更高的人将注意力放在他们正在做的大事上。我通过用较小的任务成功来激励我,用较大的任务像滚落山下的雪球一样来实现这种专注和注意力。
我现在更像建筑师了。现在我在想:这个东西如何扩展?我以前从未真正考虑过这个问题。成为 SRE 让我理解了我们的分布式系统和基础设施是如何作为一个整体工作的,并让我对我的决策的结果有了更多的了解。
使用木偶师| CircleCI 进行功能浏览器测试
与 web 应用程序的大多数交互都发生在浏览器上。用户搜索商品、填写表单、创建购物车、登录他们的个人资料以及执行许多其他任务。单元测试很棒,但是没有什么比通过与面向用户的前端交互来测试应用程序更好的了。在本教程中,您将学习并演示如何使用木偶师为浏览器编写测试。然后,您将通过在持续集成流程中自动化测试过程来更进一步。
先决条件
要遵循本教程,需要做一些事情:
所有这些安装和设置,我们可以开始教程。
克隆和运行示例应用程序
第一步是设置要测试的 web 应用程序。您需要通过运行以下命令来克隆一个演示应用程序:
git clone --single-branch --branch base-project https://github.com/CIRCLECI-GWP/browser-testing
然后,转到项目的根目录(cd browser-testing
),通过运行以下命令安装依赖项:
npm install
完全安装完依赖项后,使用以下命令运行应用程序:
node server
应用服务器将在http://localhost:5000
启动。在浏览器上访问该 URL,查看演示应用主页。
演示页面包含一个标题Welcome to the demo Web Page
,一个包含文本This is a sample text in a paragraph on the page
的段落,以及一个带有电子邮件字段和提交按钮的表单。填写并提交后,表单会将提交的电子邮件打印到屏幕上。
安装 Jest 和木偶师
您将测试演示页面,以确认它包含页面上显示的元素,并验证表单的行为。你需要两个包:
- 木偶师是浏览器测试框架。
- Jest 充当您将要编写的测试套件的测试运行程序。
使用以下命令将这些包作为开发依赖项安装:
npm install --save-dev puppeteer jest
安装好这些之后,您现在可以开始向项目中添加浏览器测试了。
使用木偶师添加测试
您将测试的第一个元素是标题和段落。测试将确认这些元素在页面上,并且包含预期的文本。
在项目的根目录下添加一个名为homepage.test.js
的新测试文件。添加此代码:
const puppeteer = require("puppeteer");
test("Confirm text on page", async () => {
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
await page.goto("http://localhost:5000");
let pageHeader = await page.$("#pageTitle");
let pageHeaderValue = await pageHeader.evaluate((el) => el.textContent);
expect(pageHeaderValue).toContain("Welcome to the demo Web Page");
let pageParagraph = await page.$("#pageParagraph");
let pageParagraphValue = await pageParagraph.evaluate(
(el) => el.textContent
);
expect(pageParagraphValue).toContain(
"This is a sample text in a paragraph on the page"
);
} finally {
await browser.close();
}
}, 120000);
这个测试用例在http://localhost:5000
启动一个新的浏览器实例并加载 web 应用。然后,它使用 CSS 选择器来定位标题和段落,以读取它们的内容。然后将标题和段落的内容与预期结果进行比较。
要运行这些测试,使用以下代码修改package.json
中的test
脚本:
...
"scripts" : {
"test" : "jest"
}
确保 web 应用程序正在运行(使用node server
)。然后运行以下命令:
npm run test
运行之后,CLI 输出显示您已经通过了测试。
PASS ./homepage.test.js (32.732 s)
✓ Confirm text on page (25962 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 41.205 s
Ran all test suites.
接下来,添加另一个测试用例来测试表单行为。在第一个测试用例下添加以下代码:
...
test("Confirm form submission output", async () => {
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
await page.goto("http://localhost:5000");
await page.type("#userEmail", "test@company.com");
await page.click("#submitButton");
let emailContainer = await page.$("#infoDisplay");
let value = await emailContainer.evaluate((el) => el.textContent);
expect(value).toContain("test@company.com");
} finally {
await browser.close();
}
}, 120000);
第二个测试用例引用 email 字段,使用它的id
属性和在字段中输入的 email ( test@company.com
)。测试引用提交按钮,并使用按钮的id
属性“点击”它。最后,确定电子邮件的显示容器,获取文本内容并与预期值(即输入的电子邮件)进行比较。
保存这个文件,然后使用npm run test
命令再次运行您的测试。CLI 输出显示测试已经通过。
PASS ./homepage.test.js (64.297 s)
✓ Confirm text on page (42118 ms)
✓ Confirm form submission output (9664 ms)
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 84.997 s
Ran all test suites.
设置 CI 管道以自动化测试
为了完成本教程的目标,我们将通过将测试过程插入到持续集成(CI)管道中来实现测试过程的自动化。每次在您的远程存储库上更新代码时,管道都会运行测试。第一步是将代码推送到 GitHub 。确保这是连接到您的 CircleCI 帐户的 GitHub 帐户。
接下来,转到 CircleCI 仪表板上的项目页面来添加项目。
点击设置项目按钮,打开设置页面。然后在弹出的模式上点击跳过这一步,因为我们将在本教程的后面手动添加我们的 CircleCI 配置。
在 Setup 页面上,点击 Use Existing Config 表示您将手动添加一个配置文件,并且不使用示例。接下来,系统会提示您下载管道的配置文件或开始构建。
点击开始建造。这个构建将会失败,因为我们还没有设置配置文件。设置它是我们的下一步。
最后一步,在项目的根目录下创建一个名为.circleci
的文件夹。在刚刚创建的文件夹中添加一个名为config.yml
的配置文件。在该文件中,输入以下代码:
version: 2.1
jobs:
build:
working_directory: ~/repo
docker:
- image: circleci/node:12-browsers
steps:
- checkout
- run:
name: Update NPM
command: "sudo npm install -g npm"
- restore_cache:
key: dependency-cache-{{ checksum "package-lock.json" }}
- run:
name: Install Dependencies
command: npm install
- save_cache:
key: dependency-cache-{{ checksum "package-lock.json" }}
paths:
- ./node_modules
- run:
name: Run the application
command: node server.js
background: true
- run:
name: Run tests
command: npm run test
在这个配置中,所需的 Node.js 映像被拉入。这个图像包含浏览器,这对运行浏览器测试很重要。配置的下一部分更新npm
。然后安装并缓存项目依赖项。
为了对应用程序运行浏览器测试,使用node server
在后台进程中启动应用程序。然后使用npm run test
命令运行测试。
提交对项目的所有更改,并推送到您的远程 GitHub 存储库。这将自动触发管道。
成功!点击 build 查看测试细节。
干得好!
结论
从应用程序用户的角度进行测试,可以获得如此多的洞察力。您可以了解应用程序的不同单元如何协同工作来帮助用户在您的应用程序中完成他们的任务。尽管如此,大多数界面/浏览器测试仍然是手工完成的。在本教程中,您已经演示了如何自动化这些类型的测试,以加速开发流程并提高生产率。功能浏览器测试通过让您的团队能够快速捕捉和响应错误,提高了您的应用程序的质量。确保与您的团队分享您成功测试的细节,以便他们也可以从这些信息中受益。
编码快乐!
Fikayo Adepoju 是 LinkedIn Learning(Lynda.com)的作者、全栈开发人员、技术作者和技术内容创建者,精通 Web 和移动技术以及 DevOps,拥有 10 多年开发可扩展分布式应用程序的经验。他为 CircleCI、Twilio、Auth0 和 New Stack 博客撰写了 40 多篇文章,并且在他的个人媒体页面上,他喜欢与尽可能多的从中受益的开发人员分享他的知识。你也可以在 Udemy 上查看他的视频课程。
功能性与非功能性软件测试
原文:https://circleci.com/blog/functional-vs-non-functional-testing/
当你想到软件测试时,首先想到的是什么?对于许多开发人员来说,单元测试和集成测试通常是他们首先想到的。这两种软件测试方法对于编写和维护高质量的产品代码库都至关重要。但是它们本身是不够的。
您的团队的测试实践应该评估整个应用程序,观察它在正确运行时如何运行的更大故事,并在发现偏差时发出警报。功能性和非功能性测试都是全面软件测试过程的重要组成部分,在每个应用层建立额外的信心。
https://www.youtube.com/embed/NgQT7miTP9M
视频
什么是功能测试?
功能测试侧重于根据一组需求或规范检查应用程序的功能。功能测试通常包括测试部分底层代码。
与单独测试单个模块相比,将实际输出与预期行为进行比较可以提供更清晰的总体情况。模块之间的交互经常是错误发生的地方。
有许多类型的功能测试:
- 单元测试(也可以用于非功能测试)
- 集成测试
- 用户接受度测试
- 闭箱测试
单元测试
API 应用程序的单元测试可能会针对测试环境中部署的系统发出请求,并将响应与文档进行比较。然而,单元测试是有限的。当应用程序在功能上偏离或倒退时,应用程序范围的功能测试通常会检测到单元测试没有检测到的变化。
集成测试
集成测试验证软件模块如何协同工作。当开发人员将代码编写为松散耦合的模块时——这通常是应该的——组件依赖于它们如何交互的显式契约。集成测试验证软件的每一部分都达到了合同的末尾,并在这些交互引入回归时生成警告。
用户接受度测试
在软件测试的用户接受阶段,开发人员向最终用户或他们的代表提供部分或全部应用程序,以模拟真实世界的交互和功能。许多健康的工程文化避免严重依赖用户验收测试,因为它不可靠,成本高,耗时。尽管如此,对于大多数应用程序来说,一些用户接受度测试是测试过程中至关重要的一部分。
闭箱测试
功能测试还可以包括完整应用程序的封闭测试。封闭盒测试从整体上处理应用程序的输出,而不检查其内部工作。当编写功能测试来补充他们的非功能测试时,许多工程师倾向于它。与最外层交互的代码被自动测试,并且只评估输出。对于只需要 API 测试的应用程序来说,这个过程很简单,因为代码只需进行 API 调用并评估结果。
当用于有用户界面的应用程序时,封闭盒测试变得越来越复杂。解决这种复杂性的一种方法是使用像 Selenium 这样复杂的测试工具。这些工具允许代码与应用程序进行交互,就好像它是 web 浏览器中的用户一样。Selenium 和类似的工具可以自动进行用户验收测试,同时提高可靠性和扩展性。然而,对用户界面应用封闭盒测试是一个具有独特挑战的复杂问题。它会迅速消耗您团队的工程带宽。
什么是非功能测试?
非功能性测试评估对功能性不重要但有助于最终用户体验的应用程序属性。负载下的性能和可靠性不是软件系统的功能组件,但肯定会影响或破坏用户体验。没有通过非功能性测试的东西并不总是导致用户会注意到的问题,但是它可以指示系统中的问题——特别是在大规模的情况下。
有许多类型的非功能性测试:
- 性能试验
- 负载测试
- 可用性测试
- 安全测试
性能试验
非功能测试类别中的一个重要过程关注性能。性能测试确保软件系统迅速响应请求。糟糕的延迟会破坏用户体验,而编写良好的性能测试通常会在用户发现问题之前就发现问题。
负载测试
负载测试是一种相关类型的非功能测试。很少有系统能像每秒响应 10,000 个请求那样每秒响应一个请求。负载测试验证系统能够处理峰值负载,并在缺乏处理工作负载峰值的资源时从容失败。
可用性测试
可用性测试衡量用户体验的质量。在很大程度上,可用性测试是一个手动过程,不能很好地扩展。不管怎样,缺乏可用性测试,尤其是在本地化应用程序时,通常会导致混乱和不直观的界面。花一些时间将这种类型的测试整合到你的软件开发过程中是值得的。
安全测试
安全性测试包括另一组非功能性测试。您的团队应该定期测试他们的应用程序,以确保它们是安全的,并能正确处理数据。安全测试的范围从自动扫描到定期渗透测试,取决于应用程序暴露于潜在威胁的程度。许多团队没有将安全测试视为他们测试套件的一部分。明智的做法是包含安全性测试,并像对待单元测试一样认真对待它。
比较功能测试和非功能测试
功能性测试确认代码正在做正确的事情,而非功能性测试验证代码正在以正确的方式做正确的事情。这两种类型都包含验证前端和后端元素和行为的方法。在开发人员可能运行的测试种类中,这两个类别之间有一些重叠。
功能测试套件是这两个类别中更为必要的。软件解决方案必须解决他们的目标问题。非功能测试所针对的实现细节和性能指标通常是细化的次要问题。一个健壮的测试方法也考虑了这些因素,尤其是当扩展是一个优先事项时。
功能测试的编写和维护通常很昂贵,执行起来也很慢。许多开发人员非常依赖单元测试,因为它们有助于测试驱动的开发,并且经常导致自我记录的代码。当代码需求发生变化时,这些测试可以快速执行并且易于修改。即使使用像 Selenium 这样的现代工具,像封闭盒测试这样的方法也需要很长时间来运行和编写。
最中立的测试方法包括功能性和非功能性测试的综合。许多开发人员遵循“测试金字塔”,这指导他们将大部分测试写成单元测试,因为他们编写和执行起来很快。
当他们在金字塔上前进时,开发人员实现更少的方法,如集成测试,然后向实践前进,如最终的用户验收测试。最终,他们更保守地使用测试方法,提供相对于他们的实现成本更低的回报。
通过将功能性和非功能性测试集成到持续集成和持续部署(CI/CD)管道中,组织可以降低与实现和维护测试过程相关的成本。
结论
测试软件应用程序没有通用的解决方案。说功能性方法比非功能性好或者反过来都太死板了。
非功能测试和验证功能的测试一样必要。许多团队认为非功能测试的优先级较低,因为它提供的改进不太引人注目。如果性能下降,用户可能会感到烦恼,但是他们仍然能够使用软件应用程序。
另一方面,当功能被破坏时,用户可能根本无法使用他们需要的功能。这与更短的执行时间和更低的成本相结合,使得功能测试成为许多团队软件测试过程的基础。
尽管如此,非功能性测试仍然扮演着重要的角色,您的团队应该找到将它们结合起来的方法。一个优秀的测试套件将验证广泛的非功能特性和组件,包括性能和可用性。
要了解更多关于测试以及如何进一步将良好的测试实践与您的持续集成工具结合的信息,请探索一些与 CircleCI 集成的测试工具。
函数式与面向对象编程| CircleCI
原文:https://circleci.com/blog/functional-vs-object-oriented-programming/
编程既是一门科学,也是一门艺术。个人偏好在决定你的编程风格方面起着很大的作用,所以当你发现自己在和一个同龄人争论时,你可能不会感到惊讶。一个正在进行的争论是在两个不同的编程范例之间的选择,这两个范例被称为函数式编程和面向对象编程。哪个更好?你应该使用哪一个?
双方的支持者都会告诉你,他们最喜欢的范式提供了一些几乎普遍适用的明显优势。你可以说这要视情况而定。在本文中,我们将着眼于这两种选择,并试图从事实中提炼出神话。目标是更好地理解这些编程方法,并准备在有意义的时候使用它们。
函数式编程
函数式编程(FP) 是最古老的编程种类之一,甚至可能是最古老的。它定义了一个构建完全依赖于函数的软件的过程。在 FP 中,开发人员编写函数来创建新函数,编写应用程序来避免共享状态或可变数据等问题。为了实现这一点,开发者经常声明性地使用 FP,而不是强制性地使用。
这意味着什么呢?
函数式编程中的关键概念
首先,理解函数在 FP 中是一等公民是很重要的,这意味着它们和其他任何值一样被对待。它们可以作为参数传递或从其他函数返回。返回函数的函数称为高阶函数。这些高阶函数使得直接从参数构造新函数成为可能。
第二个要点是不变性的概念。不可变的值是原始值,不能改变。像数字这样的值被认为是不可变的。您不能将 42 更改为 14。您只能创建一个值为 14 的新数字,并将其分配给之前使用的变量。但是新的 14 号不会影响你之前使用的 42 号。
虽然这种值处理对于诸如数字之类的原语是有意义的,但是对于诸如对象或数组之类的组合值来说可能感觉很奇怪。然而,FP 原则将所有的值都视为不可变的。更改值的唯一方法是创建一个新值,可能会使用旧值作为基值或副本。
不可变数据类型的使用允许 FP 使用纯函数。这些函数仅由其参数定义。因为参数不能改变,所以保证它们的行为是可预测的。同样的论点给出同样的结果。其他编程方法不能保证这种可预测的行为。
函数式编程的用例
尽管 FP 最初主要用于科学应用,但它在各种领域越来越受欢迎。例如,在 web 开发中,一个名为 React 的用户界面(UI)库利用 FP 原则变得声明性和易于处理。该库提倡使用不可变的状态对象(值)来反映应用程序的当前状态,而不进行更改。当开发者想要一个新的状态时,他们必须创建一个新的对象。这种方法的美妙之处在于,您可以追溯 UI 中的每次更改。所有先前的状态仍然未被触及并且可用。
虽然 FP 的根源当然是在计算机科学的学术方面,但是它的实际含义可以追溯到像 Lisp 或 Scheme 这样的语言。这些特性中的一些被融入了 JavaScript 语言,这是 FP 继续使用的一个关键因素。然而,有些语言是建立在 FP 原则之上的:F#、Clojure 和 Elixir 都是比较流行的语言。在学术界,Haskell 几十年来一直被认为是主流语言。
面向对象编程
函数式编程已经存在很长时间了,但是一些开发人员认为面向对象编程(OOP)更加传统。像 Smalltalk 或 Objective-C 这样的编程语言普及了 OOP,OOP 是在 20 世纪 70 年代末发明的。后来,C++、Java 和 C#继续将这种编程风格硬植入大多数开发人员的头脑中。
请继续阅读 OOP 中重要原则的描述和一些最常见的用例。
面向对象编程中的关键概念
在 OOP 中,开发人员将软件应用程序建模为可以相互通信的对象的集合。每个对象的接口都是一个类,一个指示函数和值可以被任何实例访问的模板。虽然这种通信能力最初被设想为允许网络通信或异步 IO 的消息传递,但后来它作为在相应对象上调用的简单函数而普及。这样的功能被称为方法。
与 FP 中的不可变对象不同,OOP 中的对象变异是游戏的一部分。因此,调用一个方法很可能也会改变对象的一些值。
许多开发人员仍然使用 OOP 的一个原因是,它是强制性编写的,尤其是在教授编程的时候。这意味着开发人员很清楚在哪里发生了什么。相反的观点是,即使使用这种命令式风格,也很难确定单个对象的当前状态。由于可变性,这可能会很快导致不可预见的后果。
面向对象编程的用例
传统上,开发人员用面向对象的方法制作了几乎所有的用户界面。这也相对简单,因为基于类的组件可以从另一个类似的组件继承它的基本结构(字段和方法)。例如,日期输入字段可以从文本输入字段继承,文本输入字段从输入框继承,输入框从控件继承。使用这种基于继承的方法,您只需要指定额外的方法,并在一些现有的方法上重新实现行为。例如,不需要再次编写键盘或鼠标处理的逻辑。
今天,OOP 是所有通用编程语言的必备特性。甚至基于 FP 的语言如 F#也直接支持 OOP 特性,如类或继承。一个很好的例子是 JavaScript,它没有马上加入标准特性,比如类或继承,而是在最近的版本中加入了它们。
正如我们已经发现的那样,这两种编程方法差异很大,足以证明在适当的时候使用这两种方法是正确的。那么如何在二者之间做出选择呢?以下是一些论据。
函数式编程与面向对象编程:争论
正如已经讨论过的,这两种方法各有利弊。计算机科学教授 Norman Ramsey 在著名的 T2 堆栈溢出答案 T3 中提供了一个有用的观点。他认为,当所有对象都是已知的,但行为可能会改变时,FP 会表现出色。相比之下,当行为已知时,OOP 是很棒的,但是实际的数据类型可能会改变。
双方的粉丝都不止这些。例如,FP 的追随者认为以纯 FP 风格编写的设计简洁的软件易于调试,并且永远不会崩溃。他们告诉你,FP 立刻给你带来了测试驱动开发的一些优势,严格应用了所有 T2 坚实原则的 OOP 本质上是 FP。虽然 SOLID 确实导致了类似于 FP 的大多数的个体函数,但是它不一定非得是 FP。例如,没有坚实的原则禁止数据突变。
热爱 OOP 的开发人员可能会因为性能或简单性的权衡而忽略一些 FP 的好处。当您只想更改单个字段时,为什么要将一个对象的所有字段复制到一个新对象中?为什么有一百万个元素的数组需要一个副本来设置一个元素?当然,您可以使用一些模式来避免制作副本,但是您仍然需要专门的数据结构。与开发人员多年来独立于 OOP 使用的直接方法相比,这里的间接程度可能令人困惑。
虽然这些方法之间有一些非常鲜明的对比,但它们也可以是互补的。没有法律禁止在软件应用程序中使用类。也没有法律规定应用程序的一般状态是可变的。
展望未来
几乎所有流行的编程语言都是多进制。它们都支持 FP,允许传递函数,或者拥有处理数据对象不变性的助手。它们还附带了面向对象的特性,比如类或继承。无论哪种方式,这种多半径方法都将继续存在。从用户的角度来看,有更多的选择几乎总是更好。
总的来说,更倾向于 FP 友好的特性似乎是可能的。通过引入对克隆数据对象、函数引用和函数组合的额外支持,语言变成了一个很好的伴侣,甚至超越了 FP。在像 C#这样的语言中,FP 友好的特性为 OOP 特性提供了一个极好的补充。这种组合甚至在 OOP 开发的应用程序中也很方便,比如当您使用某些辅助函数时。
混合 FP 和 OOP 方法的缺点是学习曲线。有些人就是因为这个原因而避免使用 C#。最初作为 Java 的一个原始的、设计优雅的替代品,最终感觉更像是一个复杂的 C++怪物。
OOP 当然不会消失,但最有可能的结果是它会找到自己的位置,与 FP 共存。诚然,副作用自由开发的理想在实践中几乎不可能实现。将日志消息写入控制台已经有副作用了。开发者必须首先发现并打开 FP 的实用性。现在开发者已经开始认识到 FP 的实用性,几乎没有理由再把 FP 的特性锁在外面。
对面向对象编程的持续支持
在这种背景下,为什么 OOP 仍然是一个可行的选择?OOP 有价值,因为它本质上是理想的工具。几乎没有什么是开发人员不能通过 OOP 实践建模的。开发者甚至可以通过 OOP 对大多数 FP 特性进行建模。
例如,考虑像传递或组合函数这样的基本事情。简而言之,这就是仿函数或委托所提供的。它只是一个对象,对应一个类,只有一个方法。
寻找共同点
很少有开发团队会仅仅为了从一种方法切换到另一种方法而改变他们的软件或编写应用程序的方式。对于一个团队来说,更有可能的是积极地重构他们的一些最基本的应用程序,以使用他们的编程语言的更新的特性。
不管怎样,未来看起来越来越混合。在未来的某个项目中,你可能会发现自己在 OOP 应用程序中使用了更多受 FP 启发的风格,或者在 FP 驱动的应用程序中使用了一些 OOP 特性。
结论
某些类型的应用程序偏爱 FP(比如编译器),而其他的应用程序更适合使用 OOP 原则(比如经典的桌面应用程序)。选择正确的编程方法取决于几个因素,比如目标编程语言、框架和您正在构建的应用程序类型。使用你觉得最舒服的,但不要忘记继续学习增加你的工具。解决问题时有大量的选择总是有益的。
使用 CircleCI | CircleCI 将 Gatsby 站点部署到 Netlify
Gatsby 是一个静态网站和应用程序生成器,它使得构建强大的基于 React 的前端应用程序变得简单而有效。GitHub 上有超过五万颗星星(在撰写本文时为 51.5k),Gatsby 是使用最广泛的 React 框架之一。Gatsby 如此受欢迎,以至于大多数托管平台都提供了对该框架的定制支持。 Netlify 就是这些平台中的一个。虽然 Netlify 对 Gatsby 的自定义支持提供了流畅的部署,但有一个主要缺点。Netlify 控制了大部分部署过程,这意味着您的团队不能执行像运行自动化测试这样的定制任务。
在本教程中,您将学习如何通过使用 CircleCI 作为连续部署服务器来接管部署过程。通过使用本教程创建的设置,您将能够在最终部署到 Netlify 之前执行构建过程中所需的任何自定义步骤。
先决条件
要遵循本教程,需要做一些事情:
安装并设置好所有这些之后,您就可以开始本教程了。
创建一个新的盖茨比网站
您首先需要的是一个部署到 Netlify 的 Gatsby 站点。在系统中您选择的任何位置运行以下命令:
npm init gatsby
该命令调用 Gatsby 安装程序并打开一个交互式 CLI 会话,在该会话中,系统会提示您回答几个问题来设置您的项目。根据下面的列表回答问题。请注意,粗体文本是为问题选择的文本回答或选项,而斜体文本是要执行的操作。
- 你想把你的网站叫做什么:Netlify Gatsby 网站
- 您希望将创建网站的文件夹命名为什么:按 Enter 键接受默认值
- 你会使用 CMS 吗:不会(或者我稍后会添加它)
- 要不要添加一个造型系统:不要(或者我以后再添加)
- 您想用其他插件安装附加功能吗:选择添加 Markdown 和 MDX 支持,点击完成,然后按回车键
- 我们可以这样做吗:按回车键确认是选项
以下是项目反应流程的 cli 输出:
What would you like to call your site?
✔ · Netlify Gatsby Site
What would you like to name the folder where your site will be created?
✔ 2021/ netlify-gatsby-site
✔ Will you be using a CMS?
· No (or I'll add it later)
✔ Would you like to install a styling system?
· No (or I'll add it later)
✔ Would you like to install additional features with other plugins?
· Add Markdown and MDX support
Thanks! Here's what we'll now do:
🛠 Create a new Gatsby site in the folder netlify-gatsby-site
🔌 Install gatsby-plugin-mdx
? Shall we do this? (Y/n) › Yes
回答完问题后,项目创建开始。在这个过程结束时,您将在netlify-gatsby-site
文件夹中创建一个 Gatsby 项目。使用以下命令运行项目:
cd netlify-gatsby-site
npm run develop
这将在本地 URL http://localhost:8000
启动 Gatsby 站点。在您的浏览器中输入此地址即可访问该网站。
设置 GitHub 项目
下一步是在 GitHub 上建立您的 Gatsby 项目。GitHub 安装完成后,您就可以在 Netlify 和 CircleCI 上安装项目了。在将您的项目推送到 GitHub 之前,您需要安装 Netlify CLI 包,作为您的 Gatsby 项目中的开发依赖项。对于 CI 环境中的部署,建议这样做,以避免中断更改。在 Gatsby 项目的根目录下,运行以下命令来安装依赖项:
npm install --save-dev netlify-cli
你现在可以将你的项目推送到 GitHub 了。一旦你的项目在 GitHub 上,创建一个新的分支。给这个分支取任何你想要的名字;对于本教程,我将把它命名为netlify-deploy-ignore
。
您可能想知道为什么需要这个分支。Netlify 需要一个项目分支来自动触发应用程序的部署。当更改被推送到这个分支时,Netlify 将启动部署过程。您希望避免 Netlify 和 CircleCI 管道并行运行两个部署进程的情况。这个新的分支充当了 Netlify 监视的诱饵。不要将更改推送到此分支。其目的是“分散”Netlify 部署过程的注意力,以便您可以使用 CircleCI 进行部署。你可以在 GitHub 上设置一个受保护的分支,这样你的团队中就没有人会误把它推上来。
创建 Netlify 应用程序
要创建新的 Netlify 应用程序,请转到您的 Netlify 仪表板,然后单击 Git 按钮中的新站点。接下来,选择 GitHub 作为您的提供商并搜索项目。
选择项目并转到下一步,为 Netlify 选择要部署的分支。选择你的诱饵分支。
接下来,点击 Deploy site 按钮,这样 Netlify 将执行您站点的第一次部署。点击链接,看起来应该是:sitename.netlify.app
。
要在 CircleCI 管道中执行自动部署,您需要从 Netlify 应用程序和帐户中获取两个配置值。
- 您刚刚创建的应用程序的应用程序 ID 可以在您的 Netlify 应用程序的站点详细信息部分找到。
- 个人访问令牌允许从您的部署管道访问您的 Netlify 帐户。在
User Settings > Applications
生成访问令牌。
将您的访问令牌保存在一个安全的地方,因为 Netlify 不允许您在创建后查看该值。你只能改变它。
在 CircleCI 建立项目
是时候在 CircleCI 上建立你的项目了。将.circleci
文件夹添加到项目的根目录。在其中,添加一个空的config.yml
文件。在下一节中,您将向该文件添加配置。将您的更改推送到 GitHub 项目。
接下来,转到 CircleCI 仪表板上的 Add Projects 页面来添加项目。
点击设置项目。这将加载一个对话框,CircleCI 自动检测您的配置文件。
单击 Let's Go 首次触发您的构建管道。构建将失败,因为您尚未向配置中添加代码。稍后您将执行此步骤。
在编写配置之前,您需要在 CircleCI 项目中添加 Netlify 应用程序 ID 和访问令牌作为环境变量。
确保您的项目是“管道”页面上当前选定的项目。点击项目设置按钮。在设置页面上,从侧面菜单中选择环境变量。在这个新页面上,点击添加环境变量按钮,输入以下信息:
NETLIFY_SITE_ID
是您的 Netlify 应用程序的应用程序 ID。NETLIFY_ACCESS_TOKEN
是您的网络个人访问令牌。
编写部署配置
该过程的最后一步是编写部署配置。打开config.yml
文件并添加以下配置:
version: 2.1
jobs:
build:
working_directory: ~/repo
docker:
- image: cimg/node:12.16
steps:
- checkout
- run:
name: Update NPM
command: "sudo npm install -g npm"
- restore_cache:
key: dependency-cache-{{ checksum "package-lock.json" }}
- run:
name: Install Dependencies
command: npm install
- save_cache:
key: dependency-cache-{{ checksum "package-lock.json" }}
paths:
- ./node_modules
- run:
name: Gatsby Build
command: GATSBY_CPU_COUNT=2 npm run build
- save_cache:
key: gatsby-public-cache-{{ .Branch }}
paths:
- ./public
- run:
name: Deploy to Netlify
command: ./node_modules/.bin/netlify deploy --site $NETLIFY_SITE_ID --auth $NETLIFY_ACCESS_TOKEN --prod --dir=public
workflows:
version: 2
build-deploy:
jobs:
- build:
filters:
branches:
only:
- main
在这个配置中,项目从存储库中签出,项目依赖项被安装和缓存。缓存完依赖项后,Gatsby build 命令npm run build
运行,在项目根目录下的public
目录中创建应用程序的生产版本。然后缓存该文件夹。
最后,Netlify CLI 使用$NETLIFY_SITE_ID
和$NETLIFY_ACCESS_TOKEN
变量部署站点。然后,工作流配置确保只有main
分支触发网络部署。
在为 CircleCI 推送这个配置以部署站点之前,请转到项目的src/pages
文件夹,并将index.js
文件中的 Gatsby 消息从you just made a Gatsby site
更改为you just deployed a Gatsby site with CircleCI
。这个新消息将显示已部署的应用程序已经发生了变化。
提交你所有的修改并推送到 GitHub。
这将自动触发部署管道和成功的构建。
单击构建以查看部署详细信息。
成功构建后,再次访问您的网站以验证您部署的更改。它应该显示新消息。
厉害!
要确认 Netlify 没有运行并行部署,请检查 Netlify 部署日志。生产部署中只有一个部署,第一个部署由分支netlify-deploy-ignore
触发。其余的没有显示分支,因为它们是由 CircleCI 管道触发的。
结论
这就是使用 CircleCI 将 Gatsby 站点定制部署到 Netlify 的情况。这种设置使您的团队能够更好地控制 Gatsby 到 Netlify 的部署,并为您提供在该过程中运行更多自定义步骤所需的灵活性。
如果你喜欢使用 Heroku 而不是 Netlify 作为你的托管平台,我们也有一个关于 T2 使用 CircleCI 管道定制部署 Heroku T3 的教程。
编码快乐!
Fikayo Adepoju 是 LinkedIn Learning(Lynda.com)的作者、全栈开发人员、技术作者和技术内容创建者,精通 Web 和移动技术以及 DevOps,拥有 10 多年开发可扩展分布式应用程序的经验。他为 CircleCI、Twilio、Auth0 和 New Stack 博客撰写了 40 多篇文章,并且在他的个人媒体页面上,他喜欢与尽可能多的从中受益的开发人员分享他的知识。你也可以在 Udemy 上查看他的视频课程。
谷歌云运行 orb | CircleCI
这篇文章将展示如何在 CI/CD 管道中使用 Google Cloud Run 平台。管道将测试应用程序的代码,构建 Docker 映像,并将映像作为 Google Cloud Run 服务部署在 Google 云平台上。
使用的技术
这篇文章假设读者对以下内容有基本的了解;
将项目添加到 CircleCI
本演示中使用的项目可在本报告中找到。如果你想继续下去,叉回购。然后,注册一个免费的 CircleCI 账户,如果你还没有的话。按照在 CircleCI 上设置构建的说明,将项目连接到 CircleCI。
Google 云设置
让我们创建与 Google Cloud Run 平台交互所需的必要凭证。这些凭证将为我们的 CI/CD 管道提供在谷歌云平台(GCP)上执行命令所需的访问权限。
创建一个 GCP 项目
在 GCP 控制台中创建一个新项目。为您的项目取一个容易记忆的名称。我们想让它易于识别,以便以后容易拆除。创建后,一定要复制project id
,因为它不同于project name
。
获取您项目的凭据
接下来,设置一个服务帐户密钥,您将使用它来创建和管理 GCP 项目中的资源。按照这里的步骤创建服务账户密钥。选择JSON
作为按键类型,点击创建。在本地保存这个.json
文件。
重要安全提示: 保护你的 Google Cloud 凭证不被发布和暴露在公共的 GitHub 存储库中。您必须非常谨慎地使用此文件中的数据,因为一旦暴露,任何拥有此信息的人都可以登录您的帐户,创建资源,并收取费用。将凭证的.json
文件名添加到项目的.gitignore
文件中,作为防止意外发布这些敏感数据的保护层。
cicekci 管道设置
接下来,我们需要更新我们的管道配置文件,以便在我们的 CI/CD 管道中使用 Google Cloud Run 平台。
编码 Google 服务帐户文件
服务帐户文件必须编码成一个base64
值,以便将该数据作为一个环境变量存储在 CircleCI 上。在终端中运行以下命令,对值进行编码并获得结果:
base64 cicd_demo_gcp_creds.json
该命令的结果将类似于以下内容:
ewogICJ0eXBlIjogInNlcnZpY2VfYWNjb3VudCIsCiAgInByb2plY3RfaWQiOiAiY2ljZC13b3Jrc2hvcHMiLAogICJwcml2YXRlX2tleV9pZCI6ICJiYTFmZDAwOThkNTE1ZTE0NzE3ZjE4NTVlOTY1NmViMTUwNDM4YTQ4IiwKICAicHJpdmF0ZV9rZXkiOiAiLS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tXG5NSUlFdlFJQkFEQU5CZ2txaGtpRzl3MEJBUUVGQUFTQ0JLY3dnZ1NqQWdFQUFvSUJBUURjT1JuRXFla3F4WUlTXG5UcHFlYkxUbWdWT3VzQkY5NTE1YkhmYWNCVlcyZ2lYWjNQeFFBMFlhK2RrYjdOTFRXV1ZoRDZzcFFwWDBxY2l6XG5GdjFZekRJbXkxMCtHYnlUNWFNV2RjTWw3ZlI2TmhZay9FeXEwNlc3U0FhV0ZnSlJkZjU4U0xWcC8yS1pBbjZ6XG5BTVdHZjM5RWxSNlhDaENmZUNNWXorQmlZd29ya3Nob3BzLmlhbS5nc2VydmljZWFjY291bnQuY29tIgp9Cg==
将结果复制到剪贴板。您将在下一节中使用它。
创建项目变量
为了让这个 CI/CD 管道在 GCP 上执行命令,我们必须在 CircleCI 上创建项目级的环境变量。这些环境变量将在后面的config.yml
文件中使用。
使用 CircleCI 仪表板创建以下项目级环境变量:
- GOOGLE_PROJECT_ID :您的 Google Cloud 项目的项目 ID 。这个值可以从 Google Cloud Dashboard 中的项目卡中检索到。
- GCP _ 项目 _ 密钥:上一节的 base64 编码结果。
- GOOGLE_COMPUTE_ZONE :针对您的部署的区域的值。
Google Cloud Run(完全托管)与使用 Anthos 的 GKE Google Cloud Run
Google Cloud Run 允许你在一个完全托管的环境中运行服务,或者在一个带有 Anthos 的 Google Kubernetes 引擎(GKE)集群上运行服务。在这篇文章中,我将阐述如何运行完全托管的 Google Cloud Run,以及如何使用 Anthos 在 GKE 集群上运行 Google Cloud Run。在这两种情况下,我将演示如何使用 Google Cloud Run orb 将 Google Cloud Run 部署集成到您的 CI/CD 管道中。
使用 Google Cloud Run(完全托管)服务创建 CI/CD 管道
现在您已经拥有了在 CircleCI 管道中使用 Google Cloud Run 平台所需的所有元素,请使用以下配置语法更新项目的config.yml
文件。
version: 2.1
orbs:
gcp-gcr: circleci/gcp-gcr@0.6.1
cloudrun: circleci/gcp-cloud-run@1.0.0
jobs:
build_test:
docker:
- image: circleci/python:3.7.4
steps:
- checkout
- run:
name: Install Python Dependencies
command: |
echo 'export PATH=~$PATH:~/.local/bin' >> $BASH_ENV && source $BASH_ENV
pip install --user -r requirements.txt
- run:
name: Run Tests
command: |
pytest
build_push_image_cloud_run_mangaged:
docker:
- image: circleci/python:3.7.4
steps:
- checkout
- setup_remote_docker:
docker_layer_caching: false
- run:
name: Build app binary and Docker image
command: |
echo 'export PATH=~$PATH:~/.local/bin' >> $BASH_ENV
echo ${GCP_PROJECT_KEY} | base64 --decode --ignore-garbage > $HOME/gcloud-service-key.json
echo 'export GOOGLE_CLOUD_KEYS=$(cat $HOME/gcloud-service-key.json)' >> $BASH_ENV
echo 'export TAG=${CIRCLE_SHA1}' >> $BASH_ENV
echo 'export IMAGE_NAME=$CIRCLE_PROJECT_REPONAME' >> $BASH_ENV && source $BASH_ENV
pip install --user -r requirements.txt
pyinstaller -F hello_world.py
docker build -t us.gcr.io/$GOOGLE_PROJECT_ID/$IMAGE_NAME -t us.gcr.io/$GOOGLE_PROJECT_ID/$IMAGE_NAME:$TAG .
- gcp-gcr/gcr-auth:
gcloud-service-key: GOOGLE_CLOUD_KEYS
google-project-id: GOOGLE_PROJECT_ID
google-compute-zone: GOOGLE_COMPUTE_ZONE
- gcp-gcr/push-image:
google-project-id: GOOGLE_PROJECT_ID
registry-url: "us.gcr.io"
image: $IMAGE_NAME
- cloudrun/deploy:
platform: "managed"
image: "us.gcr.io/$GOOGLE_PROJECT_ID/$IMAGE_NAME"
service-name: "orb-gcp-cloud-run"
region: $GOOGLE_COMPUTE_ZONE
unauthenticated: true
workflows:
build_test_deploy:
jobs:
- build_test
- build_push_image_cloud_run_mangaged:
requires:
- build_test
云运行(完全受管)配置细分
让我们分解实现 Google Cloud Run orb 的管道语法,并使用 Google Cloud Run(完全托管)服务部署应用程序。
version: 2.1
orbs:
gcp-gcr: circleci/gcp-gcr@0.6.1
cloudrun: circleci/gcp-cloud-run@1.0.0
上面的代码片段将2.1
声明为 CircleCI 平台的version
以供使用。orbs:
键指定了要包含在这个管道中的 orb。在这个例子中,我将使用circleci/gcp-gcr@0.6.1
和circleci/gcp-cloud-run@1.0.0
球体。我包含了gcp-gcr
orb 来演示在您的管道中实现多个 orb。
jobs:
build_test:
docker:
- image: circleci/python:3.7.4
steps:
- checkout
- run:
name: Install Python Dependencies
command: |
echo 'export PATH=~$PATH:~/.local/bin' >> $BASH_ENV && source $BASH_ENV
pip install --user -r requirements.txt
- run:
name: Run Tests
command: |
pytest
build_push_image_cloud_run_mangaged:
docker:
- image: circleci/python:3.7.4
steps:
- checkout
- setup_remote_docker:
docker_layer_caching: false
- run:
name: Build app binary and Docker image
command: |
echo 'export PATH=~$PATH:~/.local/bin' >> $BASH_ENV
echo ${GCP_PROJECT_KEY} | base64 --decode --ignore-garbage > $HOME/gcloud-service-key.json
echo 'export GOOGLE_CLOUD_KEYS=$(cat $HOME/gcloud-service-key.json)' >> $BASH_ENV
echo 'export TAG=${CIRCLE_SHA1}' >> $BASH_ENV
echo 'export IMAGE_NAME=$CIRCLE_PROJECT_REPONAME' >> $BASH_ENV && source $BASH_ENV
pip install --user -r requirements.txt
pyinstaller -F hello_world.py
docker build -t us.gcr.io/$GOOGLE_PROJECT_ID/$IMAGE_NAME -t us.gcr.io/$GOOGLE_PROJECT_ID/$IMAGE_NAME:$TAG .
上面的代码片段显示了jobs:
键,它是一个作业列表,代表了要在管道中执行的一组操作。这个代码片段指定了两个任务:build_test:
和build_push_image_cloud_run_mangaged:
。build_test
作业安装应用程序依赖项。然后,它执行项目的单元测试,以确保应用程序在移动到管道中的下一个作业之前通过。列出的下一个任务是build_push_image_cloud_run_mangaged:
,创建环境变量,并构建 Docker 映像,该映像将被部署到 Google Cloud Run 服务。
- gcp-gcr/gcr-auth:
gcloud-service-key: GOOGLE_CLOUD_KEYS
google-project-id: GOOGLE_PROJECT_ID
google-compute-zone: GOOGLE_COMPUTE_ZONE
上面的代码片段使用前一节中设置的环境变量,使用gcp-gcr/gcr-auth:
orb 向 Google 容器注册中心(GCR)进行身份验证。
- gcp-gcr/push-image:
google-project-id: GOOGLE_PROJECT_ID
registry-url: "us.gcr.io"
image: $IMAGE_NAME
在上面的代码片段中,push-image
命令用于将新创建的图像推送到 GCR,以便在 GCP 使用。
- cloudrun/deploy:
platform: "managed"
image: "us.gcr.io/$GOOGLE_PROJECT_ID/$IMAGE_NAME"
service-name: "orb-gcp-cloud-run"
region: $GOOGLE_COMPUTE_ZONE
unauthenticated: true
上面的代码片段使用来自cloudrun
orb 的deploy
函数来创建和部署 Google Cloud Run 服务,该服务将提供新打包的 Docker 映像。platform
参数被设置为managed
,这将服务部署到 GCP 上的完全受管环境中。
下一节将演示如何将 Docker 映像部署到 Google Cloud Run for Anthos。
为 Anthos 在 GKE 上使用 Google Cloud Run 服务创建 CI/CD 管道
上一节演示了如何将应用程序部署到完全托管的 Google Cloud Run 环境中。在这一节中,我将演示如何为 Anthos 在 GKE 上运行的 Google Cloud 部署一个应用程序。在下面的管道示例中,build_test:
作业与之前完全托管的 Google Cloud Run 示例相同,但是请注意名为build_push_image_cloud_run_gke:
的新作业,它通过 Google Cloud Run orb 将应用程序部署到在 GKE 集群上运行的 Google Cloud Run 服务。
version: 2.1
orbs:
gcp-gcr: circleci/gcp-gcr@0.6.1
cloudrun: circleci/gcp-cloud-run@1.0.0
jobs:
build_test:
docker:
- image: circleci/python:3.7.4
steps:
- checkout
- run:
name: Install Python Dependencies
command: |
echo 'export PATH=~$PATH:~/.local/bin' >> $BASH_ENV && source $BASH_ENV
pip install --user -r requirements.txt
- run:
name: Run Tests
command: |
pytest
build_push_image_cloud_run_gke:
docker:
- image: circleci/python:3.7.4
steps:
- checkout
- setup_remote_docker:
docker_layer_caching: false
- run:
name: Build app binary and Docker image
command: |
echo 'export PATH=~$PATH:~/.local/bin' >> $BASH_ENV
echo ${GCP_PROJECT_KEY} | base64 --decode --ignore-garbage > $HOME/gcloud-service-key.json
echo 'export GOOGLE_CLOUD_KEYS=$(cat $HOME/gcloud-service-key.json)' >> $BASH_ENV
echo 'export TAG=${CIRCLE_SHA1}' >> $BASH_ENV
echo 'export IMAGE_NAME=$CIRCLE_PROJECT_REPONAME' >> $BASH_ENV && source $BASH_ENV
pip install --user -r requirements.txt
pyinstaller -F hello_world.py
docker build -t us.gcr.io/$GOOGLE_PROJECT_ID/$IMAGE_NAME -t us.gcr.io/$GOOGLE_PROJECT_ID/$IMAGE_NAME:$TAG .
- gcp-gcr/gcr-auth:
gcloud-service-key: GOOGLE_CLOUD_KEYS
google-project-id: GOOGLE_PROJECT_ID
google-compute-zone: GOOGLE_COMPUTE_ZONE
- gcp-gcr/push-image:
google-project-id: GOOGLE_PROJECT_ID
registry-url: "us.gcr.io"
image: $IMAGE_NAME
- cloudrun/create_gke_cluster:
cluster-name: $CIRCLE_PROJECT_REPONAME
machine-type: "g1-small"
zone: $GOOGLE_COMPUTE_ZONE
enable-stackdriver-kubernetes: true
scopes: "cloud-platform"
- cloudrun/deploy:
platform: "gke"
image: "us.gcr.io/$GOOGLE_PROJECT_ID/$IMAGE_NAME"
cluster: $CIRCLE_PROJECT_REPONAME
service-name: $CIRCLE_PROJECT_REPONAME
cluster-location: $GOOGLE_COMPUTE_ZONE
workflows:
build_test_deploy:
jobs:
- build_test
- build_push_image_cloud_run_gke:
requires:
- build_test
云运行 GKE 配置细分
上面显示的管道示例的第一个作业已经在完全托管部分中介绍过了,所以我将跳到新作业build_push_image_cloud_run_gke:
。
build_push_image_cloud_run_gke:
docker:
- image: circleci/python:3.7.4
steps:
- checkout
- setup_remote_docker:
docker_layer_caching: false
- run:
name: Build app binary and Docker image
command: |
echo 'export PATH=~$PATH:~/.local/bin' >> $BASH_ENV
echo ${GCP_PROJECT_KEY} | base64 --decode --ignore-garbage > $HOME/gcloud-service-key.json
echo 'export GOOGLE_CLOUD_KEYS=$(cat $HOME/gcloud-service-key.json)' >> $BASH_ENV
echo 'export TAG=${CIRCLE_SHA1}' >> $BASH_ENV
echo 'export IMAGE_NAME=$CIRCLE_PROJECT_REPONAME' >> $BASH_ENV && source $BASH_ENV
pip install --user -r requirements.txt
pyinstaller -F hello_world.py
docker build -t us.gcr.io/$GOOGLE_PROJECT_ID/$IMAGE_NAME -t us.gcr.io/$GOOGLE_PROJECT_ID/$IMAGE_NAME:$TAG .
- gcp-gcr/gcr-auth:
gcloud-service-key: GOOGLE_CLOUD_KEYS
google-project-id: GOOGLE_PROJECT_ID
google-compute-zone: GOOGLE_COMPUTE_ZONE
- gcp-gcr/push-image:
google-project-id: GOOGLE_PROJECT_ID
registry-url: "us.gcr.io"
image: $IMAGE_NAME
上面的代码片段基于应用程序构建 Docker 图像,并将图像上传到 GCR。这些操作也与本文完全管理部分演示的 Docker 操作相同。
- cloudrun/create_gke_cluster:
cluster-name: $CIRCLE_PROJECT_REPONAME
machine-type: "g1-small"
zone: "us-east1"
enable-stackdriver-kubernetes: true
scopes: "cloud-platform"
- cloudrun/deploy:
platform: "gke"
image: "us.gcr.io/$GOOGLE_PROJECT_ID/$IMAGE_NAME"
cluster: $CIRCLE_PROJECT_REPONAME
service-name: $CIRCLE_PROJECT_REPONAME
cluster-location: $GOOGLE_COMPUTE_ZONE
workflows:
build_test_deploy:
jobs:
- build_test
- build_push_image_cloud_run_gke:
requires:
- build_test
在上面的代码片段中,管道使用cloudrun
orb 将 Google Cloud Run 应用部署到 GKE 集群。cloudrun/create_gke_cluster:
命令创建了一个新的 GKE 集群,Google Cloud Run 应用程序将部署在这里。接下来,cloudrun/deploy:
命令将应用程序部署到新创建的 GKE 集群。该应用程序正在被部署到 Kubernetes 集群,这可能需要几分钟的时间,因此在此过程中请耐心等待。这将比其他操作花费更长的时间。
包扎
这篇文章展示了如何使用 Google Cloud Run orb 在 CI/CD 管道中自动构建、测试和部署应用程序到 Google Cloud Run 平台。在 CircleCI 管道中使用 orb 为将应用程序部署到 Google Cloud Run 平台提供了一个干净、简洁且经过充分测试的解决方案。
感谢阅读!
Kubernetes 管理的微服务| CircleCI
整体架构是现代应用规模和复杂性持续增长的结果。当应用程序很小的时候,诸如消除 bug 或添加新功能、更新 UI 或 UX,或者实现额外的安全性等事情都是由同一个团队完成的。将会有一个中央存储库,在一个地方存放满足所有业务需求的所有代码。随着应用程序的增长,不同的职责开始被分配给具有特定角色和功能的各个团队。这些单独的团队有特定的角色,但是他们仍然需要在同一个集中的代码库上操作,这导致了跨团队的依赖性和代码不能合并的可能性。微服务的引入有望通过将应用程序分成独立的服务来消除团队之间的交叉工作,每个服务提供一个特定的功能。这种架构最有益的方面是快速扩展、增加可靠性和更快的开发时间。
管理您的微服务
容器用于在微服务之间提供必要的隔离层。随着应用程序的复杂性及其在云中的服务之间的交互的增长,为控制多个服务如何在多个容器中运行而开发的编排工具成为了一种需求。截至目前,Kubernetes 是唯一一个可以从亚马逊(EKS)、微软(AKS)和谷歌(GKE)这三大云服务提供商那里获得的容器编排解决方案。由于这些项目提供的灵活性、可靠性和透明性,越来越依赖云服务来部署应用程序的同时,OSS 的使用也在增加。Kubernetes 是开源标准组织 CNCF 最受欢迎的项目,并且已经证明是编排工具的领导者。
微服务方法为您的架构带来的好处是有代价的。一个应用程序可能需要很多很多服务,包括来自第三方和/或 OSS 项目的专有服务。单独来说,这些服务可能更容易管理,或者在第三方和 OSS 的情况下,可能由其他人来管理它们,但是所有这些服务的行为和操作的互联方式可能非常复杂。Kubernetes 解决方案不仅难以实现,而且难以更新和调试。这就是您选择使用哪种 CI 工具如此重要的原因。您需要一个 CI 工具,它允许您将 Kubernetes 与您已经使用的所有服务一起使用。
面临一个共同的问题
使用 CircleCI 的 orbs,您可以为您管道中最重要的服务获得开箱即用的解决方案。orb 是 CircleCI config 的可重用、可共享的开源包,支持这些服务的即时集成。它们允许针对常见问题的众包解决方案。我们这里关注的是执行主要操作的 orb,比如部署到 GKE,但是其他的也允许发送关于您的项目的定制 Slack 通知。关键的好处是,您可以访问所有这些服务,而不必自己学习集成它们。要在登录 GCP、构建和部署 Docker 映像,然后将该映像部署到 GKE 集群之后向 USERID1 发送自定义 Slack 通知,只需通过导入 Slack 和GCP-GKEorb 来更新它们的.circleci/config.yml
:
orbs:
slack: circleci/slack@x.y.z
gke: circleci/gcp-gke@x.y.z
然后运行gke/publish-and-rollout-image
后的job
中的slack/notify
命令,并带有所需的参数:
jobs:
- build
- gke/publish-and-rollout-image:
deployment: k8s-deployment-name
container: container-name
image: image-name
- slack/notify:
mentions: ‘USERID1’
message: ‘deployment to GKE’
虽然一个精明的高级 DevOps 工程师可能能够将此功能编写到他们选择的 CI 工具的配置中,但 CircelCI 的 orbs 消除了这种开发,并以一个正在工作并经过测试的社区支持的集成来取代它。slack/notify
命令本身超过 125 行代码。整个松弛球体几乎有 500 行。没有一个使用 CircleCI 的团队需要自己编写代码。
CircleCI 球体是使用 Kubernetes 的最简单方法。你是只想安装kubectl
还是kops
? Kubernetes orb 可以帮你安装。您是否使用 Kubernetes 部署到 GKE?在上面的例子中,我展示了如何用 GCP-GKE 球体轻松实现这一点。也许你正在使用 Helm 来部署你的 Kubernetes。我们有头盔球来做这件事。无论您如何使用 Kubernetes,CircleCI 是唯一可以让您快速启动并运行的 CI 工具,这样您就可以将时间花在开发项目上,而不是部署管道上。
你能做什么
你还想从当前的 Kubernetes orb 中看到其他的特性吗?由于 orb 是开源的,您可以通过批准和合并您的 PR 来向现有 orb 添加功能。你也可以制造一个问题,看看是否有社区支持开发。你有没有一个用例让你觉得与当前的 Kubernetes orbs 不同?您可以自己创作一个并将其贡献给社区。我们甚至发布了为 orb 创建自动化构建、测试和部署管道的最佳实践(第 1 部分和第 2 部分)来帮助您。查看 orbs 注册表中所有可用的 Orbs。
微服务允许您的团队利用第三方服务和 OSS,消除了内部开发这些常用工具和资源的需要。有了 orb,您的团队只需要知道如何使用这些服务,而不需要知道如何集成或管理它们。
Google bin auth-Kubernetes | circle ci
原文:https://circleci.com/blog/get-started-with-google-binary-authorization/
CircleCI 的二进制授权 orb 的演练
在 Next’19 上,Google 宣布二进制授权的正式发布,这是一种针对部署在 Google Kubernetes 引擎上的容器图像的安全控制,CircleCI 是其发布合作伙伴。我们的二进制授权 orb 简化了使用 CircleCI 构建、测试和部署的映像的验证过程,确保只有那些在 CI/CD 过程中由可信机构签名的映像才能在 GKE 上运行。
二进制授权,像 Grafeas 的 Kritis ,它的开源、云不可知的对等物,使用一组不同的 RESTful 资源来管理和认证软件发布过程:
- Policies :描述在被特定证明者授权后,哪些容器映像可以被部署到特定的 Kubernetes 集群的规则集;
- 证明者:通过创建和签署证明来验证容器映像的部署准备状态的指定方,机器或人;
- 证明:证明者证明单个映像满足部署所需的所有条件的声明。
这些概念与 CircleCI 的功能相吻合,如受限上下文,它将秘密和环境变量的集合传递给特定的用户组,以及手动批准工作。总之,这些资源允许开发-运营团队根据他们的需求和规范,使用自动和手动检查的组合来平衡部署时间和可靠性/安全性,从而精心设计全面的软件供应链安全流程。
CircleCI 的 orb 让二进制授权很容易上手。一个作业create-attestation
可以引导您完成创建策略、证明者和证明的整个过程。使用 orb 构建一个全新的 GKE 集群,或者直接引用一个已经存在的集群。即时制定政策,或者自己制定政策。orb 甚至将生成并存储 PGP 密钥对,由证明者用来签署证明(通过 Google 的云密钥管理服务对非对称密钥的支持是 orb 路线图的下一步)。唯一的先决条件是谷歌云平台中的单个项目,或者对于一个多项目设置,三个独立的 GCP 项目(部署者、证明者、证明)。
与 CircleCI 的Google Container Registry orb配对,二进制授权 orb 可以在 YAML 的几行代码中提供完整的部署解决方案,如这个simple-deploy-attested-image
示例所示:
version: 2.1
orbs:
gcp-gcr: circleci/gcp-gcr@x.y.z
bin-authz: circleci/gcp-binary-authorization@x.y.z
workflows:
push_sign_deploy:
jobs:
- gcp-gcr/build_and_push_image:
context: your-context # context containing any required env vars
image: your-image # your image name
registry-url: gcr.io # default value, here for clarity
tag: your-tag # default value
- bin-authz/create-attestation:
context: your-context
attestor: $CIRCLE_USERNAME # default value
keypair-email: email.address@used.to.generate.keypair.com
gke-cluster-name: your-GKE-cluster-name
use-note-file: true
note-filepath: your-container-analysis-note.json
use-policy-file: true
policy-filepath: your-binauthz-policy-file.yaml
image-path: gcr.io/$GOOGLE_PROJECT_ID/your-image
image-tag: your-tag
requires: [gcp-gcr/build_and_push_image]
deployment-steps:
- run: |
kubectl run your-server \
--image gcr.io/$GOOGLE_PROJECT_ID/your-image@$YOUR_IMAGE_DIGEST \
--port 8080
二进制授权 orb 有大量的参数,但是不要被淹没——它们被设计为合理的默认值,在大多数用例中最大限度地减少了样板文件。如需进一步指导,请参见 orb 的其他使用示例(其 GitHub 库也有额外的说明)。
最后,由于所有 CircleCI orbs 都是开源的,如果你想在这个 orb 中看到其他东西,我们总是欢迎问题和拉请求—我们活跃的 orb 开发者和用户社区可以帮助解决任何关于这个或任何其他 orb 的问题。
CircleCI - CircleCI 上的黄瓜入门
原文:https://circleci.com/blog/getting-started-with-cucumber-on-circleci/
来自出版商的说明:您已经找到了我们的一些旧内容,这些内容可能已经过时和/或不正确。尝试在我们的文档或博客中搜索最新信息。
Cucumber 是一个行为驱动开发(BDD)工具,用于开发 web 应用程序的验收测试。出于本文的目的,我将假设您的 CircleCI 设置运行顺利,并将重点放在【Cucumber 是什么,如何很好地使用它,以及如何将其与您的 CircleCI 设置集成。
黄瓜到底是什么?
Cucumber 是一个 BDD 工具,你可以用它来验证你的应用程序的功能。cumber 测试是用一种叫做“ Gherkin 的语言编写的,它用一种自然的、类似语言的语法来表达期望的行为和软件的预期结果。BDD 不同于传统的自动化测试,因为测试既不是代码级的单元测试,也不是与 UI 交互的应用程序级脚本。BDD 测试表达了测试的一组先决条件,然后表达了测试本身,然后是预期的结果。结合一些文档(可以很容易地以一种小黄瓜友好的方式格式化),一组 Cucumber BDD 测试也可以作为一组全面的文档,供产品所有者或开发人员/QA 人员在将来审查。对于主要语言不是英语的团队,小黄瓜支持多种语言。
当时给定的
黄瓜测试的基本结构是“给定-何时-然后”格式。
“给定”是测试的设置。您可以使用 GIVEN 来设置测试所需的数据类型。您使用 GIVEN 来设置状态。
“何时”是测试的动作。WHEN 描述了您希望针对在测试的给定部分中设置的状态执行的操作。
“然后”是预期的结果。你用 THEN 来陈述你希望测试的结果是什么。
请注意,GIVEN、WHEN 和 THEN 都支持使用“and”关键字的多个步骤。这里有一个例子:
- 鉴于简有活跃的档案
- 她的资料显示萨姆是她的朋友
- 她的档案里没有朋友比尔
- 当她输入新的公共状态更新时
- 然后,Sam 应该会看到她新的公共状态更新
- 比尔应该看不到她新的公开状态更新
功能和场景
一大堆“给定时间”的步骤很快就会变得笨拙。Gherkin 提供了一种将测试组织成特性和场景的方法。一个特性是一个高层次的类别,它很好地映射到一个用户故事或者你的团队用于基本开发单元的任何东西。一个特性由一个或多个场景组成,一个场景由给定的 When Then 步骤组成。(上面的给定时间示例是一个场景。)你可以把一个场景想象成一个测试用例,把一个特性想象成一组逻辑测试用例。
步骤定义和挂钩
该工具需要一些后端编码,以便正确运行其测试。Given-When-Then 中的每一步都需要一个步骤定义才能执行。您可以使用与您的步骤相匹配的正则表达式,以及当正则表达式匹配时要执行的 Ruby 代码块来设置步骤定义。步骤定义可以跨场景重用。
钩子是您在测试运行之前和之后设置和拆除测试状态的方式,特别是为了保持测试数据库的良好状态。
与 CircleCI 集成
将您的黄瓜测试与 CircleCI 集成非常简单。Cucumber 有一些用于测试结果输出的格式化程序插件。使用 JUnit 格式化程序并配置 Cucumber 输出到$CIRCLE_TEST_REPORTS/cucumber
目录。 CircleCI 文档页面建议将以下 YAML 添加到您的 circle.yml:
test:
override:
- mkdir -p $CIRCLE_TEST_REPORTS/cucumber
- bundle exec cucumber --format junit --out $CIRCLE_TEST_REPORTS/cucumber/junit.xml
很简单。如果您喜欢 JSON 格式化程序,文档页面还显示了如何配置 circle.yml 文件。
这个配置允许 CircleCI 查看您的黄瓜测试是通过还是失败,并且您可以配置 CircleCI 如何响应失败的黄瓜测试。
Cucumber 是一个强大的工具,用来表达软件系统的期望行为,并将其集成到 CircleCI 构建中,可以为您的开发过程带来很多价值。
Kubernetes 入门:如何设置您的第一个集群
原文:https://circleci.com/blog/getting-started-with-kubernetes-how-to-set-up-your-first-cluster/
Kubernetes 是部署和扩展复杂分布式系统的优秀工具,但众所周知,开始使用 Kubernetes 是一个挑战。大多数 Kubernetes 教程使用类似于 Minikube 这样的工具来帮助您入门,但它并没有教您多少关于配置生产就绪集群的知识。
在本文中,我们将采用一种不同的方法,并向您展示如何使用亚马逊弹性 Kubernetes 服务(亚马逊 EKS)和 Terraform 建立一个真实的、生产就绪的 Kubernetes 集群。
介绍 Terraform
Hashicorp 的 Terraform 是一个基础设施即代码(IaC)解决方案,允许您以声明方式定义您的云基础设施的所需配置。使用 Terraform CLI,您可以在本地或作为自动化 CI/CD 管道的一部分提供此配置。
Terraform 类似于云平台提供的配置工具,如 AWS CloudFormation 或 Azure Resource Manager ,但它的优势是与提供商无关。如果你不熟悉 Terraform,我们建议你首先阅读他们的AWS入门指南,了解最重要的概念。
定义基础设施
让我们构建一个 Terraform 配置,逐步配置亚马逊 EKS 集群和 AWS 虚拟私有云(VPC)。
创建包含以下内容的main.tf
文件:
provider "aws" {
region = "eu-west-1"
}
data "aws_availability_zones" "azs" {
state = "available"
}
locals {
cluster_name = "eks-circleci-cluster"
}
在这个文件中,我们首先设置 AWS 提供者,将区域设置为eu-west-1
。请随意将其更改为任何其他 AWS 区域。
AWS 提供者将检查各个地方是否有有效的凭证可以使用,所以一定要设置这些凭证。
然后,我们获取可以在该区域使用的可用性区域。这使得更改区域变得更加容易,而不需要任何其他更改。我们还将集群名称设置为一个变量,因为我们将多次使用它。您也可以更改该值。
让我们来配置 VPC。将以下内容添加到文件中:
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 2.48"
name = "eks-circleci-vpc"
cidr = "10.0.0.0/16"
azs = slice(data.aws_availability_zones.azs.names, 0, 2)
private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
public_subnets = ["10.0.3.0/24", "10.0.4.0/24"]
enable_nat_gateway = true
single_nat_gateway = true
enable_dns_hostnames = true
tags = {
"kubernetes.io/cluster/${local.cluster_name}" = "shared"
}
public_subnet_tags = {
"kubernetes.io/cluster/${local.cluster_name}" = "shared"
"kubernetes.io/role/elb" = "1"
}
private_subnet_tags = {
"kubernetes.io/cluster/${local.cluster_name}" = "shared"
"kubernetes.io/role/internal-elb" = "1"
}
}
通过使用 AWS VPC 模块,我们极大地简化了 VPC 的创建。我们将 VPC 配置为使用部署 Terraform 模板的区域中的前两个 az。这是 EKS 要求的 az 的最小数量。
为了节约成本,我们只配置一个 NAT 网关。AWS VPC 模块将正确地设置路由表,以通过这个单一 NAT 网关路由所有内容。我们还为 VPC 启用了 DNS 主机名,因为这是 EKS 的要求。
最后,我们设置 EKS 所需的标记,以便它可以发现其子网,并知道在哪里放置公共和私有负载平衡器。
接下来,让我们使用 AWS EKS 模块来配置 EKS 集群。
module "eks" {
source = "terraform-aws-modules/eks/aws"
version = "~> 12.2"
cluster_name = local.cluster_name
cluster_version = "1.17"
subnets = module.vpc.private_subnets
vpc_id = module.vpc.vpc_id
worker_groups = [
{
instance_type = "t3.large"
asg_max_size = 1
}
]
}
我们将集群配置为使用我们已经创建的 VPC,并使用一个t3.large
实例定义一个单独的 worker 组。这将足以在集群中创建一个简单的测试资源,同时最小化成本。
最后,将以下配置添加到文件中:
data "aws_eks_cluster" "cluster" {
name = module.eks.cluster_id
}
data "aws_eks_cluster_auth" "cluster" {
name = module.eks.cluster_id
}
provider "kubernetes" {
version = "~> 1.9"
host = data.aws_eks_cluster.cluster.endpoint
cluster_ca_certificate = base64decode(data.aws_eks_cluster.cluster.certificate_authority.0.data)
token = data.aws_eks_cluster_auth.cluster.token
load_config_file = false
}
output "kubectl_config" {
description = "kubectl config that can be used to authenticate with the cluster"
value = module.eks.kubeconfig
}
我们从亚马逊 EKS 集群配置中获取一些数据,并将 Terraform Kubernetes 提供者配置为通过集群进行身份验证。当 AWS EKS 模块在集群中创建 configmap 时,该提供程序也在其中使用,这将授予当前通过身份验证的 AWS 用户对集群的管理权限。这是一个 EKS 特有的方法,用于授权 AWS 实体访问集群。
最后,output
块将显示向群集进行身份验证所需的信息——在我们调配完群集后会有更多相关信息。
我们现在有了一个地形配置,完全可以启动 EKS 集群。让我们应用这个配置,并在集群中创建一个测试资源。
供应 Kubernetes 集群
配置您的 shell 以认证terra form AWS 提供商。您的工作目录与我们刚刚创建 Terraform 文件的目录相同,初始化工作空间:
$ terraform init
Initializing modules...
Downloading terraform-aws-modules/eks/aws 12.2.0 for eks...
- eks in .terraform/modules/eks/terraform-aws-eks-12.2.0
- eks.node_groups in .terraform/modules/eks/terraform-aws-eks-12.2.0/modules/node_groups
Downloading terraform-aws-modules/vpc/aws 2.48.0 for vpc...
- vpc in .terraform/modules/vpc/terraform-aws-vpc-2.48.0
Initializing the backend...
Initializing provider plugins...
- Checking for available provider plugins...
- Downloading plugin for provider "random" (hashicorp/random) 2.3.0...
- Downloading plugin for provider "aws" (hashicorp/aws) 3.3.0...
- Downloading plugin for provider "kubernetes" (hashicorp/kubernetes) 1.12.0...
- Downloading plugin for provider "local" (hashicorp/local) 1.4.0...
- Downloading plugin for provider "null" (hashicorp/null) 2.1.2...
- Downloading plugin for provider "template" (hashicorp/template) 2.1.2...
Terraform has been successfully initialized!
[...]
terraform init
命令下载配置文件中包含的所有提供程序。我们现在可以应用和调配 VPC 和集群。
注意 : 这将需要 10 到 15 分钟才能完成。
$ terraform apply
[...]
Plan: 40 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
[...]
Apply complete! Resources: 40 added, 0 changed, 0 destroyed.
Outputs:
[...]
就这样:我们现在有了一个完全启动并运行的亚马逊 EKS 集群。
让我们部署一个 pod,并通过负载平衡器公开它,以确保我们的集群按预期工作。
要使用集群进行身份验证,您需要安装 kubectl 和 aws-iam-authenticator 。在terraform apply
末尾的Outputs
部分包含了你可以添加到你的 kubeconfig 文件(或者一个临时的新文件)中的细节。完成后,让我们创建一个新的部署并公开它:
$ kubectl create deployment nginx --image=nginx
deployment.apps/nginx created
$ kubectl expose deployment/nginx --port=80 --type=LoadBalancer
service/nginx exposed
$ kubectl get service nginx
从最终输出中获取EXTERNAL-IP
值——这是 AWS 负载平衡器的 DNS 条目。DNS 传播可能需要几分钟时间。当它打开时,你会看到“欢迎使用 nginx!”页面。成功!
更简单的方法:CircleCI aws-eks orb
您已经学习了一种构建亚马逊 EKS 集群的方法。然而,组装配置并使其保持最新是——并将继续是——相当多的(手动)工作。
幸运的是,CircleCI aws-eks orb 可以帮上忙。CircleCI orbs 包含预打包的配置代码,使其更容易与其他开发工具集成。这只是宝珠注册表中众多可用宝珠中的一个。
aws-eks orb 可以自动启动、测试和拆除亚马逊 eks 集群。您可以使用它来创建强大的工作流,在干净、完全隔离的临时 EKS 集群中测试应用程序。让我们试一试。
CircleCI 帐户是开始使用 orb 的主要先决条件。注册 CircleCI 并在 CircleCI 项目中将 Git 存储库连接到您的帐户。
在这个项目中,转到设置下的环境变量选项卡,添加以下变量,以便项目可以通过 AWS 进行身份验证。确保 AWS IAM 用户拥有创建 EKS 集群及其依赖项所需的权限。将 region 变量的值设置为要预配集群的区域。
接下来,在 Git 存储库中创建.circleci/config.yml
文件,并向其中添加以下内容:
version: 2.1
orbs:
aws-eks: circleci/aws-eks@1.0.0
kubernetes: circleci/kubernetes@0.11.1
jobs:
test-cluster:
executor: aws-eks/python3
parameters:
cluster-name:
description: |
Name of the EKS cluster
type: string
steps:
- kubernetes/install
- aws-eks/update-kubeconfig-with-authenticator:
cluster-name: << parameters.cluster-name >>
- run:
command: |
kubectl get services
name: Test cluster
workflows:
deployment:
jobs:
- aws-eks/create-cluster:
cluster-name: my-first-cluster
- test-cluster:
cluster-name: my-first-cluster
requires:
- aws-eks/create-cluster
- aws-eks/delete-cluster:
cluster-name: my-first-cluster
requires:
- test-cluster
该文件配置了一个包含三个作业的工作流:
- 使用来自 aws-eks orb 的
create-cluster
命令,使用 eksctl 实用程序创建集群及其依赖项 - 运行一个简单的测试来验证集群是否按预期工作
- 破坏集群
将这个文件提交到您的存储库中,CircleCI 将自动启动工作流,这将需要 15 到 20 分钟。当然,您可以在集群创建之后添加所有需要的步骤,比如提供资源和运行测试。
与我们前面讨论的创建亚马逊 eks 集群的 Terraform 方法相比,aws-eks orb 大大简化并加快了管理 EKS 集群生命周期的过程。EKS 集群本身的复杂性,以及它的依赖项(比如 VPC)的配置,都被完全抽象掉了。这是一个低维护的解决方案,它允许您将精力集中在构建具有自动化测试的有价值的持续集成工作流上。
后续步骤
您已经了解到创建您的第一个 Kubernetes 集群并不困难或可怕。Terraform 提供了一种定义集群基础设施的简单方法。通过简单的 CLI 命令,您可以轻松调配已定义的基础架构。
CircleCI orb 进一步简化了这一过程。无需编写自己的 Terraform 代码或运行任何命令,您也可以达到相同的最终结果。
学习这个的最好方法就是自己动手。首先使用 Terraform 代码及其 CLI 手动创建集群。然后,尝试 CircleCI,看看使用 aws-eks orb 创建一个集群是多么容易和快速。
Sander 是一名对自动化充满热情的云工程师。他喜欢解决技术和组织方面的挑战,以帮助公司在云中用更少的资源做更多的事情。这包括支持开发人员自治、平台工程和云原生解决方案等主题。他主要通过整合概念和工具来实现这一点,如代码基础设施、监控和日志记录、安全性和 CI/CD。
Nest.js APIs | CircleCI 持续集成入门
原文:https://circleci.com/blog/getting-started-with-nestjs-and-automatic-testing/
本教程涵盖:
- 设置和连接 Nest.js 应用程序
- 使用 Nest.js 应用程序创建产品
- 编写、运行和自动化测试
Nest.js 是一个用 TypeScript 构建的可伸缩、高效的服务器端 Node.js 框架。创建 Nest.js 是为了向 Node.js 开发环境提供一种结构化设计模式。它的灵感来自于 Angular.js ,并在引擎盖下使用了 Express.js 。Nest.js 与大多数 Express.js 中间件兼容。
在本教程中,我将带领您使用 Nest.js 构建一个 RESTful API。本教程将让您熟悉 Nest.js 的基本原理和构建块。我还将演示为每个 API 端点编写测试的推荐方法。我将通过向您展示如何使用 CircleCI 自动化测试过程来结束本教程。
先决条件
要想从本教程中获得最大收益,您需要具备以下几点:
我们的教程是平台无关的,但是使用 CircleCI 作为例子。如果你没有 CircleCI 账号,请在 注册一个免费的 。
我们在本文中构建的 RESTful API 将提供端点来创建带有名称、描述和价格的产品。我们将编辑、删除和检索单个产品,还将检索保存在数据库中的整个产品列表。
本教程使用 MySQL 作为首选的关系数据库,并将其与 TypeORM 结合使用。但是 Nest.js 是数据库不可知的,所以您可以选择使用您喜欢的任何数据库。你可以在这里找到更多关于数据库和 Nest.js 的细节。
设置 Nest.js 应用程序
运行以下命令创建新的应用程序:
nest new nest-starter-testing
运行nest
命令后,会提示您选择一个包管理器。选择npm
并按回车键开始安装 Nest.js。该过程在nest-starter-testing
文件夹中创建一个新项目,并安装其所需的所有依赖项。在运行应用程序之前,使用npm
安装一个验证库,您将在本教程的后面使用它。
npm install class-validator --save
进入应用程序文件夹,使用命令启动应用程序:
// move into the project
cd nest-starter-testing
// start the server
npm run start:dev
这将在默认的3000
端口上启动应用程序。在您喜爱的浏览器中导航至http://localhost:3000
进行查看。
配置 Nest.js 并将其连接到数据库
TypeORM 是一个流行的对象关系映射器(ORM ),用于 TypeScript 和 JavaScript 应用程序。为了便于与 Nest.js 应用程序集成,您需要为它安装一个附带的包,以及 MySQL 的 Node.js 驱动程序。为此,通过按 CTRL + C 停止应用程序运行,然后运行以下命令:
npm install --save @nestjs/typeorm typeorm mysql
当安装过程完成时,您可以将TypeOrmModule
导入到应用程序的根目录中。
更新 TypeScript 根模块
Nest.js 的构建块,模块是用@Module
修饰的 TypeScript 文件。模块提供了 Nest.js 用来组织应用程序结构的元数据。./src/app.module.ts
中的根模块是顶层模块。Nest.js 建议将一个大型应用程序分解成多个模块。它有助于维护应用程序的结构。
要创建与数据库的连接,打开./src/app.module.ts
文件并用以下代码替换其内容:
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { join } from 'path';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'mysql',
host: 'localhost',
port: 3306,
username: DB_USER,
password: DB_PASSWORD,
database: 'test_db',
entities: [join(__dirname, '**', '*.entity.{ts,js}')],
synchronize: true,
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
注 : 用你的证件代替DB_USER
和DB_PASSWORD
。
我们通过将TypeOrmModule
导入到根AppModule
中并指定连接选项,建立了与数据库的连接。其中包括数据库详细信息和实体文件的存储目录。我将在下一节更详细地介绍实体文件。
配置数据库连接
在本教程开始的先决条件中,我提到了 MySQL 下载页面。下载后,您需要配置数据库,使其适用于此应用程序。
在您的终端中,通过运行以下命令登录 MySQL:
mysql -u root -p
输入您在 MySQL 安装过程中设置的密码。现在运行:
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password';
用您的密码替换“密码”。
该命令为 MySQL 的 Node.js 驱动程序设置首选身份验证。要创建数据库,请运行:
CREATE DATABASE test_db;
为 Nest.js 应用程序创建产品模块、服务和控制器
现在您已经配置了数据库连接,我们将开始为应用程序创建更多的结构。
生成模块
首先为Product
生成一个模块。这将是一个新模块,用于对与产品相关的所有项目进行分组。首先运行以下命令:
nest generate module product
上面的命令将在src
目录下创建一个新的product
文件夹,在product.module.ts
文件中定义ProductModule
,并通过导入新创建的ProductModule
自动更新app.module.ts
文件中的根模块。./src/product/product.module.ts
文件暂时为空,如下所示:
import { Module } from '@nestjs/common';
@Module({})
export class ProductModule {}
创建实体
为了为 Nest.js 应用程序创建合适的数据库模式,TypeORM 支持创建实体。实体是映射到特定数据库表的类。在这种情况下,它是产品表。
按照 Nest.js 应用程序的正确结构,在src/product
文件夹中创建一个新文件,并将其命名为product.entity.ts
。然后将这段代码粘贴到其中:
import { PrimaryGeneratedColumn, BaseEntity, Column, Entity } from 'typeorm';
@Entity()
export class Product extends BaseEntity {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@Column()
description: string;
@Column()
price: string;
}
使用从typeorm
模块导入的装饰器,我们为产品表创建了四列。其中包括唯一标识产品的主键列。
创建数据传输对象
数据传输对象(DTO)有助于为进入应用程序的数据创建和验证正确的数据结构。例如,当您从前端向 Node.js 后端发送 HTTP POST 请求时,您需要从表单中提取发布的内容,并将其解析为后端代码可以轻松使用的格式。DTO 帮助指定从请求体中提取的对象的形状,并提供了一种轻松插入验证的方法。
要为该应用程序设置 DTO,请在src/product
目录中创建一个新文件夹,并将其命名为dto
。接下来,在新创建的文件夹中创建一个文件,并将其命名为create-product.dto.ts
。使用以下内容:
import { IsString } from 'class-validator';
export class CreateProductDTO {
@IsString()
name: string;
@IsString()
description: string;
@IsString()
price: string;
}
这里,我们定义了一个表示CreateProductDTO
的类,还添加了一些验证来确保字段的数据类型是字符串。接下来,我们将创建一个存储库来帮助将数据直接保存到应用程序数据库中。
创建自定义存储库
通常,像 TypeORM 这样的 ORM 中的存储库主要作为持久层。它包含的方法有:
这有助于与应用程序的数据库进行通信。在本教程中,我们将为我们的产品实体创建一个扩展 TypeORM 基本存储库的自定义存储库,并为特定查询创建一些自定义方法。首先导航到src/product
文件夹,创建一个名为product.repository.ts
的新文件。完成后,将以下内容粘贴到其中:
import { Repository, EntityRepository } from 'typeorm';
import { Product } from './product.entity';
import { CreateProductDTO } from './dto/create-product.dto';
@EntityRepository(Product)
export class ProductRepository extends Repository<Product> {
public async createProduct(
createProductDto: CreateProductDTO,
): Promise<Product> {
const { name, description, price } = createProductDto;
const product = new Product();
product.name = name;
product.description = description;
product.price = price;
await product.save();
return product;
}
public async editProduct(
createProductDto: CreateProductDTO,
editedProduct: Product,
): Promise<Product> {
const { name, description, price } = createProductDto;
editedProduct.name = name;
editedProduct.description = description;
editedProduct.price = price;
await editedProduct.save();
return editedProduct;
}
}
从上面的代码中,我们定义了两个方法:
createProduct()
:该方法将createProductDto
类作为参数,该类将用于提取 HTTP 请求的主体。然后我们析构createProductDto
,用这些值创造一个新产品。editProduct
:在这里,需要编辑的产品的详细信息被传递给这个方法,根据客户端的新值,指定的详细信息将被相应地更新并保存在数据库中。
生成 Nest.js 服务
服务,也称为提供者,是 Nest.js 中的另一个构建块,被归类到关注点分离原则下。它旨在处理和抽象复杂的业务逻辑,并返回适当的响应。Nest.js 中的所有服务都用@Injectable()
decorator 修饰,这使得将服务注入任何其他文件变得容易,比如控制器和模块。
使用以下命令为产品创建服务:
nest generate service product
运行上面的命令后,您将在终端上看到以下输出:
CREATE /src/product/product.service.spec.ts (467 bytes)
CREATE /src/product/product.service.ts (91 bytes)
UPDATE /src/product/product.module.ts (167 bytes)
nest
命令在src/product
文件夹中创建了两个新文件。这些是:
product.service.spec.ts
文件将用于为将在产品服务文件中创建的方法编写单元测试。product.service.ts
文件保存了应用程序的所有业务逻辑。
nest
命令还导入了新创建的服务,并将其添加到了product.module.ts
文件中。
接下来,您将使用创建和检索所有产品的方法填充product.service.ts
文件,以及获取、更新和删除特定产品的细节。打开文件并用以下内容替换其内容:
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Product } from './product.entity';
import { CreateProductDTO } from './dto/create-product.dto';
import { ProductRepository } from './product.repository';
@Injectable()
export class ProductService {
constructor(
@InjectRepository(ProductRepository)
private productRepository: ProductRepository,
) {}
public async createProduct(
createProductDto: CreateProductDTO,
): Promise<Product> {
return await this.productRepository.createProduct(createProductDto);
}
public async getProducts(): Promise<Product[]> {
return await this.productRepository.find();
}
public async getProduct(productId: number): Promise<Product> {
const foundProduct = await this.productRepository.findOne(productId);
if (!foundProduct) {
throw new NotFoundException('Product not found');
}
return foundProduct;
}
public async editProduct(
productId: number,
createProductDto: CreateProductDTO,
): Promise<Product> {
const editedProduct = await this.productRepository.findOne(productId);
if (!editedProduct) {
throw new NotFoundException('Product not found');
}
return this.productRepository.editProduct(createProductDto, editedProduct);
}
public async deleteProduct(productId: number): Promise<void> {
await this.productRepository.delete(productId);
}
}
在这里,我们导入了应用程序所需的模块,并创建了单独的方法来:
- 创建新产品:
createProduct()
- 获取所有创建的产品:
getProducts()
- 检索单个产品的详细信息:
getProduct()
- 编辑特定产品的详细信息:
editProduct()
- 删除单个产品:
deleteProduct()
值得注意的是,我们将之前创建的ProductRepository
注入到这个服务中,以便轻松地与数据库进行交互和通信。以下是显示这一点的文件片段:
...
constructor(
@InjectRepository(ProductRepository)
private productRepository: ProductRepository,
) {}
...
只有当我们也将ProductRepository
导入到产品模块中时,这才起作用。我们将在教程的后面做这件事。
生成 Nest.js 控制器
Nest.js 中控制器的职责是接收和处理来自应用程序客户端的传入 HTTP 请求,并根据业务逻辑返回适当的响应。路由机制由附着在每个控制器顶部的装饰器@Controller()
控制,通常决定哪个控制器接收哪个请求。要为我们的项目创建新的控制器文件,请从终端运行以下命令:
nest generate controller product --no-spec
您将看到以下输出。
CREATE /src/product/product.controller.ts (103 bytes)
UPDATE /src/product/product.module.ts (261 bytes)
因为我们不会为这个控制器编写测试,所以我们使用了--no-spec
选项来指示nest
命令不要为控制器生成.spec.ts
文件。打开src/product/product.controller.ts
文件,将其代码替换为:
import {
Controller,
Post,
Body,
Get,
Patch,
Param,
Delete,
} from '@nestjs/common';
import { ProductService } from './product.service';
import { CreateProductDTO } from './dto/create-product.dto';
import { Product } from './product.entity';
@Controller('product')
export class ProductController {
constructor(private productService: ProductService) {}
@Post('create')
public async createProduct(
@Body() createProductDto: CreateProductDTO,
): Promise<Product> {
const product = await this.productService.createProduct(createProductDto);
return product;
}
@Get('all')
public async getProducts(): Promise<Product[]> {
const products = await this.productService.getProducts();
return products;
}
@Get('/:productId')
public async getProduct(@Param('productId') productId: number) {
const product = await this.productService.getProduct(productId);
return product;
}
@Patch('/edit/:productId')
public async editProduct(
@Body() createProductDto: CreateProductDTO,
@Param('productId') productId: number,
): Promise<Product> {
const product = await this.productService.editProduct(
productId,
createProductDto,
);
return product;
}
@Delete('/delete/:productId')
public async deleteProduct(@Param('productId') productId: number) {
const deletedProduct = await this.productService.deleteProduct(productId);
return deletedProduct;
}
}
在这个文件中,我们导入了必要的模块来处理 HTTP 请求,并将之前创建的ProductService
注入到控制器中。这是通过构造函数使用已经在ProductService
中定义的函数来完成的。接下来,我们创建了这些异步方法:
createProduct()
方法用于处理客户端发送的 POST HTTP 请求,以创建新产品并将其保存在数据库中。getProducts()
方法从数据库中获取完整的产品列表。getProduct()
方法将productId
作为参数,并使用它从数据库中检索具有唯一productId
的产品的详细信息。editProduct()
方法用于编辑特定产品的详细信息。deleteProduct()
方法也接受惟一的productId
来标识特定的产品并从数据库中删除它。
这里需要注意的另一件重要事情是,我们定义的每个异步方法都有一个元数据装饰器作为 HTTP 动词。它们接受一个前缀,Nest.js 使用这个前缀来进一步标识和指向应该处理请求并做出相应响应的方法。
例如,我们创建的ProductController
有一个前缀product
和一个名为createProduct()
的方法,该方法接受前缀create
。这意味着任何指向product/create
( http://localhost:3000/product/create
)的GET
请求都将由createProduct()
方法处理。这个过程对于在这个ProductController
中定义的其他方法也是一样的。
更新产品模块
现在已经创建了控制器和服务,并使用nest
命令将其自动添加到ProductModule
中,我们需要更新ProductModule
。打开./src/product/product.module.ts
并用以下代码更新其内容:
import { Module } from '@nestjs/common';
import { ProductController } from './product.controller';
import { ProductService } from './product.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ProductRepository } from './product.repository';
@Module({
imports: [TypeOrmModule.forFeature([ProductRepository])], // add this
controllers: [ProductController],
providers: [ProductService],
})
export class ProductModule {}
这里,我们将ProductRepository
类传递给了TypeOrm.forFeature()
方法。这将允许使用ProductRepository
类。
应用程序现在已经准备好了,我们可以运行它来测试到目前为止创建的所有端点。从终端运行以下命令:
npm run start:dev
这将在http://localhost:3000
启动应用程序。此时,您可以使用类似于 Postman 的工具来测试 API。Postman 是一个测试工具,用于在部署到生产环境之前确认和检查 API 的行为。
使用 Nest.js 应用程序创建产品
用产品的name
、description
和price
创建一个到http://localhost:3000/product/create
端点的 POST HTTP 请求。
获取所有产品
对http://localhost:3000/product/all
进行 GET HTTP 请求调用,以检索创建的产品的完整列表。
获取产品
为了检索单个产品的详细信息,我们向http://localhost:3000/product/2
端点发送了一个 GET HTTP 请求。请注意,2
是我们感兴趣的产品的唯一productId
。你也可以尝试其他值。
编辑产品
向http://localhost:3000/product/edit/2
端点发送补丁 HTTP 请求,更新用2
的productId
标识的产品详情。
为 Nest.js 应用程序编写测试
既然我们的 API 如预期的那样工作,在这一节中,我们将把重点放在为之前创建的ProductService
类中定义的方法编写测试上。感觉只测试应用程序的这一部分比较合适,因为它处理大部分业务逻辑。
Nest.js 带有内置的测试基础设施,这意味着我们不必在测试方面设置太多配置。尽管 Nest.js 与测试工具无关,但它提供了开箱即用的集成。Jest 将提供 assert 函数和 test-double 工具来帮助模仿。
目前,product.service.spec.ts
文件的代码是:
import { Test, TestingModule } from '@nestjs/testing';
import { ProductService } from './product.service';
describe('ProductService', () => {
let service: ProductService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [ProductService],
}).compile();
service = module.get<ProductService>(ProductService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});
我们将添加更多的测试,使其完全覆盖所有在ProductService
中定义的方法。
为“创建”和“获取”产品方法编写测试
请记住,我们并没有使用测试驱动的开发方法来启动这个项目。因此,我们将编写测试来确保ProductService
中的所有业务逻辑接收到适当的参数并返回预期的响应。首先,打开product.service.spec.ts
文件并用以下内容替换其内容:
import { Test, TestingModule } from '@nestjs/testing';
import { ProductService } from './product.service';
import { ProductRepository } from './product.repository';
import { NotFoundException } from '@nestjs/common';
describe('ProductService', () => {
let productService;
let productRepository;
const mockProductRepository = () => ({
createProduct: jest.fn(),
find: jest.fn(),
findOne: jest.fn(),
delete: jest.fn(),
});
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
ProductService,
{
provide: ProductRepository,
useFactory: mockProductRepository,
},
],
}).compile();
productService = await module.get<ProductService>(ProductService);
productRepository = await module.get<ProductRepository>(ProductRepository);
});
describe('createProduct', () => {
it('should save a product in the database', async () => {
productRepository.createProduct.mockResolvedValue('someProduct');
expect(productRepository.createProduct).not.toHaveBeenCalled();
const createProductDto = {
name: 'sample name',
description: 'sample description',
price: 'sample price',
};
const result = await productService.createProduct(createProductDto);
expect(productRepository.createProduct).toHaveBeenCalledWith(
createProductDto,
);
expect(result).toEqual('someProduct');
});
});
describe('getProducts', () => {
it('should get all products', async () => {
productRepository.find.mockResolvedValue('someProducts');
expect(productRepository.find).not.toHaveBeenCalled();
const result = await productService.getProducts();
expect(productRepository.find).toHaveBeenCalled();
expect(result).toEqual('someProducts');
});
});
});
首先,我们从@nestjs/testing
模块导入了Test
和TestingModule
包。这提供了方法createTestingModule
,它创建了一个测试模块,该模块将作为测试中前面定义的模块。在这个testingModule
中,providers
数组由ProductService
和一个mockProductRepository
组成,用来模仿使用工厂定制的ProductRepository
。
然后,我们创建了测试套件的两个不同组件,以确保我们可以创建产品并检索产品列表。
让我们再添加几个脚本来测试在应用程序中检索和删除单个产品的功能。仍然在product.service.spec.ts
文件中,通过在我们现有的测试脚本下面添加以下代码来更新它:
import { Test, TestingModule } from '@nestjs/testing';
import { ProductService } from './product.service';
import { ProductRepository } from './product.repository';
import { NotFoundException } from '@nestjs/common';
describe('ProductService', () => {
...
describe('getProduct', () => {
it('should retrieve a product with an ID', async () => {
const mockProduct = {
name: 'Test name',
description: 'Test description',
price: 'Test price',
};
productRepository.findOne.mockResolvedValue(mockProduct);
const result = await productService.getProduct(1);
expect(result).toEqual(mockProduct);
expect(productRepository.findOne).toHaveBeenCalledWith(1);
});
it('throws an error as a product is not found', () => {
productRepository.findOne.mockResolvedValue(null);
expect(productService.getProduct(1)).rejects.toThrow(NotFoundException);
});
});
describe('deleteProduct', () => {
it('should delete product', async () => {
productRepository.delete.mockResolvedValue(1);
expect(productRepository.delete).not.toHaveBeenCalled();
await productService.deleteProduct(1);
expect(productRepository.delete).toHaveBeenCalledWith(1);
});
});
});
为了获得特定的产品,我们简单地创建了一个带有一些默认细节的mockProduct
,并验证了我们可以检索和删除产品。
查看 GitHub 上的获取完整的测试脚本。
在本地运行测试
在运行测试之前,您应该删除为位于src/app.controller.spec.ts
中的AppController
创建的测试文件,如果您希望为其编写测试,您可以稍后手动创建该文件。现在,继续运行测试,使用:
npm run test
输出将是这样的:
> nest-starter-testing@0.0.1 test /Users/dominic/workspace/personal/circleci-gwp/nest-starter-testing
> jest
PASS src/app.controller.spec.ts
PASS src/product/product.service.spec.ts
Test Suites: 2 passed, 2 total
Tests: 6 passed, 6 total
Snapshots: 0 total
Time: 3.148 s
Ran all test suites.
自动化测试
现在,您已经用 Nest.js 构建了一个完整的 RESTful API,并对其业务逻辑进行了测试。接下来,您需要添加配置文件来设置与 CircleCI 的持续集成。持续集成有助于确保代码的更新不会破坏任何现有的功能。一旦测试被推送到 GitHub 存储库,它就会自动运行。
首先,创建一个名为.circleci
的文件夹,并在其中创建一个名为config.yml
的新文件。打开新文件并将以下代码粘贴到其中:
version: 2.1
orbs:
node: circleci/node@3.0.0
jobs:
build-and-test:
executor:
name: node/default
steps:
- checkout
- node/install-packages
- run:
command: npm run test
workflows:
build-and-test:
jobs:
- build-and-test
这里,我们指定了要使用的 CircleCI 版本,并使用 CircleCI Node orb 来设置和安装 Node.js。最后一个命令是实际的测试命令,它运行我们的测试。
在 CircleCI 建立项目
通过将导航到此页面,在 CircleCI 上创建一个帐户。接下来,如果您是任何组织的一部分,您将需要选择您希望工作的组织来用 CircleCI 设置您的存储库。
一旦你进入项目页面,找到我们之前在 GitHub 上创建的项目,点击设置项目。
这将显示一个配置页面,允许您选择想要使用的 CircleCI 配置文件。这默认为位于主分支.circleci/config.yaml
的配置。
现在点击设置项目。
按照提示,点击手动添加,因为我们已经包含了配置文件。您将看到您的管道开始自动运行并通过。
这个构建只有一个任务:build-and-test
。作业中的所有步骤都在一个单元中执行,要么在一个新容器中执行,要么在一个虚拟机中执行。
您也可以点击工单查看步骤。步骤是在作业期间运行的可执行命令的集合
单击这些步骤会显示更多详细信息。例如,点击npm run test
步骤。
所有测试都成功运行,并且显示出与本地运行测试时类似的输出。随后,你要做的就是给你的项目增加更多的特性,编写更多的测试,推送到 GitHub。持续集成管道将自动运行,测试将被执行。
使用 Nest.js 构建自己的 RESTful API
Nest.js 鼓励并加强 web 应用程序的优秀结构。它帮助您的团队组织工作并遵循最佳实践。在本教程中,我们学习了如何使用 Nest.js 构建 RESTful APIs,并使用 Postman 测试功能。最后,我们编写了几个测试,并使用 CircleCI 自动化了它们。
在本教程中,我们重点测试了ProductService
。如果您想进一步探索,您可以将获得的知识应用到应用程序的其他部分。
该应用程序的完整源代码在 GitHub 上。
要了解如何向 NestJS GraphQL 项目添加单元和集成测试,并使用 CircleCI 自动化测试过程,请访问NestJS graph QL 项目的持续集成博客文章。
Oluyemi 是一名拥有电信工程背景的技术爱好者。出于对解决用户日常遇到的问题的浓厚兴趣,他冒险进入编程领域,并从那时起将他的问题解决技能用于构建 web 和移动软件。Oluyemi 是一名热衷于分享知识的全栈软件工程师,他在世界各地的几个博客上发表了大量技术文章和博客文章。作为技术专家,他的爱好包括尝试新的编程语言和框架。
充分利用 Docker 和工作流,第 2 部分:关于工作流的一切
原文:https://circleci.com/blog/getting-the-most-out-of-docker-and-workflows-part-2-all-about-workflows/
来自出版商的说明:您已经找到了我们的一些旧内容,这些内容可能已经过时和/或不正确。尝试在我们的文档或博客中搜索最新信息。
在的上一期中,我们看到了 Docker 映像如何为构建过程增加功能和定制。在这一期中,我们将向您展示如何通过使用 CircleCI 2.0 Workflows 特性来增强这种能力。
详细的工作流程
简单来说, Workflows 在作业之间增加了一个简单的协调层。让我们从想象一个简单的工作流程开始:
工作流 DAG
工作流配置节和实时工作流运行(需要登录 CircleCI):
workflows:
version: 2
blog-demo-1:
jobs:
- bundle_dependencies
- rake_test:
requires:
- bundle_dependencies
- precompile_assets:
requires:
- bundle_dependencies
- deploy:
requires:
- rake_test
- precompile_assets
blog-demo-1
工作流程由 4 个任务组成。bundle_dependencies
作业更新和缓存依赖关系。然后我们“扇出”成两个并行的作业- rake_test
和precompile_assets.
,它们中的每一个都将恢复依赖关系并完成自己的工作。如果rake_test
和precompile_assets
都成功,我们就“扇入”到deploy
工作中。
利益
我们可以轻松地完成一个内联所有运行步骤的单一作业。通过引入工作流,我们获得了什么?
显式并行=更快的构建
当它们并行发生时,事情发生得更快。
工作流提供的显式“扇出”并行性可以显著减少构建时间,特别是当项目随着时间的推移变得越来越复杂,并且引入了越来越多的独立可并行化任务,如代码覆盖。
在上面的例子中,rake_test
和precompile_assets
受益于这种并行性。
每个作业可能在不同的环境中运行
在我们上面的例子中,deploy
作业运行在“机器”中,而不是 Docker 容器中。您有机会为每个作业指定不同的 Docker 图像和 resource_class 。
为了降低成本和最大限度地减少构建时间,用户可能希望使用具有强大资源的功能丰富的容器来运行一些常见的前驱步骤,然后分散到许多轻量级作业中,以实现快速并行构建。
重复性-从失败重新运行
如果某项工作因暂时性问题(如不稳定的文本或外部服务的临时中断)而在工作流程中失败,您不必从头开始重新启动工作流程。“重新运行失败的作业”功能允许工作流以失败的作业为起点继续运行。
如果没有工作流,您将总是不得不重新运行整个构建。
向您的 VCS 提供商报告详细状态
通过工作流,您的 VCS 提供商(例如 Github)将获得一个状态列表——每个作业一个状态——这样可以更容易地一眼看出故障发生在哪里,并且您可以直接导航到失败的作业。
结尾部分
在这篇博文中,我们简要介绍了 Circle 2.0 的工作流特性。在下一期中,我们将逐步添加一些高级特性,包括:
- 工作区转发
- 手动审批作业
- 分支和标签过滤
Golang Gin-gonic RESTful API 的自动化测试
本教程涵盖:
- 使用 Gin-gonic 框架用 Golang 构建 RESTful API
- 为端点编写和运行测试
- 自动化测试
Gin 是一个用 Golang 编写的高性能 HTTP web 框架。它包含路由和现成中间件等特性和功能。这有助于减少样板代码,提高生产率,并简化构建微服务的过程。
在本教程中,我将指导你使用 Gin-gonic 框架构建一个 RESTful API。我还将带领您构建一个 API 来管理公司的基本细节。这个 API 将允许您创建、编辑、删除和检索公司列表。
为了简单起见,我不会在本教程中讨论数据持久性。相反,我们将使用一个虚拟的公司列表,我们可以相应地更新或删除。这听起来可能很简单,但足以让您开始用 Golang 构建健壮的 API 和单元测试。
先决条件
您将需要以下内容来充分利用本教程:
我们的教程是平台无关的,但是使用 CircleCI 作为例子。如果你没有 CircleCI 账号,请在 注册一个免费的 。
入门指南
首先,通过终端导航到您的开发文件夹,并使用以下命令为项目创建一个新文件夹:
mkdir golang-company-api
cd golang-company-api
前面的命令创建了一个名为golang-company-api
的文件夹,并导航到其中。
接下来,通过发出以下命令初始化项目中的一个 Go 模块:
go mod init golang-company-api
这将创建一个go.mod
文件,其中将列出项目的依赖项以供跟踪。
安装项目的依赖项
如上所述,这个项目将使用 Gin 框架作为外部依赖。从项目的根目录发出以下命令,安装最新版本的 Gin 和其他依赖项:
go get -u github.com/gin-gonic/gin github.com/stretchr/testify github.com/rs/xid
一旦安装过程成功,您就可以访问 Gin 和应用程序中的以下软件包:
- evidence是 Golang 最受欢迎的测试包之一
- XID 是一个全球唯一的 ID 生成器库。
创建主页
现在,在项目的根目录下创建一个名为main.go
的文件。这将是应用程序的入口点,也将包含负责所有功能的大多数功能。打开新文件,并使用以下内容:
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func HomepageHandler(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message":"Welcome to the Tech Company listing API with Golang"})
}
func main() {
router := gin.Default()
router.GET("/", HomepageHandler)
router.Run()
}
这段代码导入了 Gin 和一个提供 http 客户端和服务器实现的 net/http 包。它创建了一个HomepageHandler()
方法来处理应用程序主页上的响应。
最后,main()
函数初始化一个新的 Gin 路由器,为主页定义 HTTP 动词,并通过调用 Gin 实例的Run()
在默认端口8080
上运行一个 HTTP 服务器。
运行项目
运行项目:
go run main.go
该命令在默认端口8080
上运行应用程序。去http://localhost:8080
复习一下。
既然应用程序按预期工作,您就可以开始实现 API 端点所需的逻辑了。现在,使用 CTRL+C 停止应用程序的运行,然后按下 Enter 。
创建 REST APIs
在继续之前,您需要定义一个保存公司信息的数据结构。这将包含公司的属性和字段。每个公司都有一个ID
、Name
、CEO
的名字和Revenue
——公司预计的年收入。
定义公司模式
使用 Go 结构来定义这个模型。在main.go
文件中,声明以下结构:
type Company struct {
ID string `json:"id"`
Name string `json:"name"`
CEO string `json:"ceo"`
Revenue string `json:"revenue"`
}
要轻松地将每个字段映射到特定的名称,请使用反勾号指定每个字段上的标签。这允许您发送符合 JSON 命名约定的适当响应。
定义全局变量
接下来,定义一个全局变量来表示公司,并用一些虚拟数据初始化该变量。在main.go
文件中,在Company
结构之后添加:
var companies = []Company{
{ID: "1", Name: "Dell", CEO: "Michael Dell", Revenue: "92.2 billion"},
{ID: "2", Name: "Netflix", CEO: "Reed Hastings", Revenue: "20.2 billion"},
{ID: "3", Name: "Microsoft", CEO: "Satya Nadella", Revenue: "320 million"},
}
创建新公司
接下来,定义创建新公司所需的逻辑。在main.go
文件中创建一个新方法,将其命名为*NewCompanyHandler*
,并使用以下代码:
func NewCompanyHandler(c *gin.Context) {
var newCompany Company
if err := c.ShouldBindJSON(&newCompany); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
newCompany.ID = xid.New().String()
companies = append(companies, newCompany)
c.JSON(http.StatusCreated, newCompany)
}
这个代码片段将传入的请求体绑定到一个Company
struct 实例中,然后指定一个惟一的ID
。它将newCompany
添加到公司列表中。如果有错误,则返回错误响应,否则返回成功响应。
获取公司列表
要检索公司列表,定义一个*GetCompaniesHandler*
方法:
func GetCompaniesHandler(c *gin.Context) {
c.JSON(http.StatusOK, companies)
}
这使用了c.JSON()
方法将companies
数组映射到 JSON 并返回它。
更新公司
要更新现有公司的详细信息,请使用以下内容定义一个名为*UpdateCompanyHandler*
的方法:
func UpdateCompanyHandler(c *gin.Context) {
id := c.Param("id")
var company Company
if err := c.ShouldBindJSON(&company); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
index := -1
for i := 0; i < len(companies); i++ {
if companies[i].ID == id {
index = 1
}
}
if index == -1 {
c.JSON(http.StatusNotFound, gin.H{
"error": "Company not found",
})
return
}
companies[index] = company
c.JSON(http.StatusOK, company)
}
这个代码片段使用c.Param()
方法从请求 URL 中获取公司的惟一id
。它检查该记录是否存在于公司列表中,然后相应地更新指定的公司。
删除公司
使用以下内容创建一个*DeleteCompanyHandler*
方法:
func DeleteCompanyHandler(c *gin.Context) {
id := c.Param("id")
index := -1
for i := 0; i < len(companies); i++ {
if companies[i].ID == id {
index = 1
}
}
if index == -1 {
c.JSON(http.StatusNotFound, gin.H{
"error": "Company not found",
})
return
}
companies = append(companies[:index], companies[index+1:]...)
c.JSON(http.StatusOK, gin.H{
"message": "Company has been deleted",
})
}
与*UpdateCompanyHandler*
类似,这个代码片段中的方法使用惟一标识符来定位需要从列表中删除的公司的详细信息。它删除公司详细信息,并返回一个成功的响应。
设置 API 路由处理程序
接下来,注册所有适当的端点,并将它们映射到前面定义的方法。如下所示更新main()
:
func main() {
router := gin.Default()
router.GET("/", HomepageHandler)
router.GET("/companies", GetCompaniesHandler)
router.POST("/company", NewCompanyHandler)
router.PUT("/company/:id", UpdateCompanyHandler)
router.DELETE("/company/:id", DeleteCompanyHandler)
router.Run()
}
如果您使用的是支持包自动导入的代码编辑器或 IDE,那么这将会得到更新。如果您没有使用该类型的编辑器或 IDE,请确保import
与下面的代码片段匹配:
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/rs/xid"
)
测试应用程序
在定义的所需方法和注册的单个端点中,返回到终端并使用go run main.go
再次运行应用程序。这将在端口8080
上启动应用程序
创建新公司
使用 Postman 或您喜欢的 API 测试工具对此进行测试。向http://localhost:8080/
公司发送 HTTP POST 请求。使用以下数据作为请求有效负载:
{
"name":"Shrima Pizza",
"ceo": "Demo CEO",
"revenue":"300 million"
}
正在检索公司列表
要检索公司列表,将 HTTP GET
请求设置为http://localhost:8080/companies
。
为端点编写测试
既然您的应用程序正在按预期工作,那么就专注于为所有为处理 API 端点的逻辑而创建的方法编写单元测试。
Golang 开箱即用,安装了一个测试包,使得编写测试更加容易。首先,创建一个名为main_test.go
的文件,并用以下内容填充它:
package main
import "github.com/gin-gonic/gin"
func SetUpRouter() *gin.Engine{
router := gin.Default()
return router
}
这是一个返回 Gin 路由器实例的方法。在测试每个端点的其他功能时,它会很方便。
注意: 项目中的每个测试文件都必须以_test.go
结尾,每个测试方法都必须以Test
开头。这是有效测试的标准命名约定。
测试主页响应
在main_test.go
文件中,定义一个*TestHomepageHandler*
方法并使用以下代码:
func TestHomepageHandler(t *testing.T) {
mockResponse := `{"message":"Welcome to the Tech Company listing API with Golang"}`
r := SetUpRouter()
r.GET("/", HomepageHandler)
req, _ := http.NewRequest("GET", "/", nil)
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
responseData, _ := ioutil.ReadAll(w.Body)
assert.Equal(t, mockResponse, string(responseData))
assert.Equal(t, http.StatusOK, w.Code)
}
这个测试脚本使用 Gin 引擎设置一个服务器,并向主页/
发出一个GET
请求。然后,它使用 evident 包中的assert
属性来检查状态代码和响应有效负载。
测试创建新的公司端点
要为您的 API 测试/company
端点,创建一个*TestNewCompanyHandler*
方法并使用以下代码:
func TestNewCompanyHandler(t *testing.T) {
r := SetUpRouter()
r.POST("/company", NewCompanyHandler)
companyId := xid.New().String()
company := Company{
ID: companyId,
Name: "Demo Company",
CEO: "Demo CEO",
Revenue: "35 million",
}
jsonValue, _ := json.Marshal(company)
req, _ := http.NewRequest("POST", "/company", bytes.NewBuffer(jsonValue))
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusCreated, w.Code)
}
这个代码片段发出一个带有示例负载的POST
请求,并检查返回的响应代码是否是201
StatusCreated
。
测试获取公司端点
接下来是测试GET /companies
资源的方法。用下面的代码定义*TestGetCompaniesHandler*
方法:
func TestGetCompaniesHandler(t *testing.T) {
r := SetUpRouter()
r.GET("/companies", GetCompaniesHandler)
req, _ := http.NewRequest("GET", "/companies", nil)
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
var companies []Company
json.Unmarshal(w.Body.Bytes(), &companies)
assert.Equal(t, http.StatusOK, w.Code)
assert.NotEmpty(t, companies)
}
这段代码向/companies
端点发出一个GET
请求,并确保返回的有效负载不为空。它还声明状态代码是200
。
测试更新公司端点
最后一个测试是针对负责更新公司详细信息的 HTTP 处理程序。在main_test.go
文件中使用以下代码片段:
func TestUpdateCompanyHandler(t *testing.T) {
r := SetUpRouter()
r.PUT("/company/:id", UpdateCompanyHandler)
company := Company{
ID: `2`,
Name: "Demo Company",
CEO: "Demo CEO",
Revenue: "35 million",
}
jsonValue, _ := json.Marshal(company)
reqFound, _ := http.NewRequest("PUT", "/company/"+company.ID, bytes.NewBuffer(jsonValue))
w := httptest.NewRecorder()
r.ServeHTTP(w, reqFound)
assert.Equal(t, http.StatusOK, w.Code)
reqNotFound, _ := http.NewRequest("PUT", "/company/12", bytes.NewBuffer(jsonValue))
w = httptest.NewRecorder()
r.ServeHTTP(w, reqNotFound)
assert.Equal(t, http.StatusNotFound, w.Code)
}
这向company/:id
端点发送了两个 HTTP PUT
请求。一个具有有效负载和有效公司 id,另一个具有不存在的 ID。有效调用将返回成功响应码,无效调用将返回StatusNotFound
。
更新main_test.go
文件中的导入部分:
import (
"bytes"
"encoding/json"
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
"github.com/rs/xid"
"github.com/stretchr/testify/assert"
)
在本地运行测试
现在,通过发出以下命令来运行测试:
go test
要禁用 Gin 调试日志并启用详细模式,请运行带有-V
标志的命令:
GIN_MODE=release go test -v
自动化测试
通过在 CircleCI 上创建一个持续集成管道来自动化测试。要添加所需的配置,创建一个名为.circleci
的文件夹,并在其中创建一个名为config.yml
的新文件。打开新文件并将以下代码粘贴到其中:
version: 2.1
orbs:
go: circleci/go@1.7.1
jobs:
build:
executor:
name: go/default
tag: "1.16"
steps:
- checkout
- go/load-cache
- go/mod-download
- go/save-cache
- run:
name: Run tests
command: go test -v
这个脚本为 CircleCI 拉入 Go orb。这个 orb 允许执行常见的 Go 相关任务,如安装 Go、下载模块和缓存。然后,它检查远程存储库,并发出运行我们的测试的命令。
接下来,在 GitHub 上建立一个存储库,并将项目链接到 CircleCI。查看将您的项目推送到 GitHub 以获取指导。
连接到 CircleCI
登录您的 CircleCI 帐户。如果你注册了你的 GitHub 账户,你所有的库都可以在你项目的仪表盘上看到。
点击设置项目按钮。将提示您是否已经在项目中定义了 CircleCI 的配置文件。输入分支名称(对于本教程,我们使用main
)。点击设置项目按钮完成该过程。
通过单击工作流程中的作业,您可以查看所有步骤。
您可以通过点击作业来获得作业的更多详细信息,例如Run tests
作业。
你有它!
结论
GitHub 上有超过 50k 颗星,令人惊讶的是 Gin 越来越受欢迎,并逐渐成为 Golang 开发人员构建高效 API 的首选。
在本教程中,我向您展示了如何使用 Golang 和 Gin 构建 REST API。我带领您为每个端点编写了一个单元测试,并使用 GitHub 和 CircleCI 为它建立了一个持续集成管道。希望你能将所学应用到团队的项目中。
点击 GitHub 上的查看示例项目的代码。
Oluyemi 是一名拥有电信工程背景的技术爱好者。出于对解决用户日常遇到的问题的浓厚兴趣,他冒险进入编程领域,并从那时起将他解决问题的技能用于构建 web 和移动软件。Oluyemi 是一名热衷于分享知识的全栈软件工程师,他在世界各地的几个博客上发表了大量技术文章和博客文章。由于精通技术,他的爱好包括尝试新的编程语言和框架。
Oluyemi 是一名拥有电信工程背景的技术爱好者。出于对解决用户日常遇到的问题的浓厚兴趣,他冒险进入编程领域,并从那时起将他的问题解决技能用于构建 web 和移动软件。Oluyemi 是一名热衷于分享知识的全栈软件工程师,他在世界各地的几个博客上发表了大量技术文章和博客文章。作为技术专家,他的爱好包括尝试新的编程语言和框架。
从 Git 分离头状态| CircleCI 中恢复
2005 年 Git 作为源代码管理系统的引入从根本上改变了软件开发的过程。Git 允许开发人员维护代码更改或提交的历史,如果出现问题,可以在几秒钟内恢复到以前的提交。它通过允许分支来保持不同特性的代码分离,并无缝合并不同人的提交,从而使协作变得更加容易。它速度快,可伸缩,比旧版本控制工具如 Apache Subversion (SVN)和 Concurrent Versions System (CVS)拥有更多的命令和灵活性。
然而,学习 Git 比学习 SVN 或 CVS 更复杂。复杂的命令和不太直观的用户界面有时会导致不需要的状态,包括称为分离头的状态。在本文中,我们将探讨什么是 Git 分离头状态以及导致它的一些情况。然后,我们将演示如何在一个分离的头中保存或放弃更改,以便您可以从这种情况中快速恢复。
头分离是什么意思?
在 Git 中,HEAD 指的是当前签出分支的最新提交。然而,在一个分离的 HEAD 状态中,HEAD 不指向任何分支,而是指向一个特定的提交或远程存储库。
下图是正常状态下的 Git 头,指向主分支中的最新提交。
在此图中,HEAD 指向当前分支中每个提交的最新提交和当前签出分支。
头也是多分支工作时的常见状态。
在这种情况下,您有两个分支,主分支和功能分支。因为您被检出到特征分支,所以 HEAD 指向那里。您可以使用以下 Git 命令创建这个场景:
git branch feature
git checkout feature
git commit -m “checked out to feature”
git checkout Main
git commit
git commit -m “Latest commit”
git checkout feature
在上面的两个图中,HEAD 指向当前签出分支中最近的提交,这是它的正常状态。在 Git 中,您还可以检查特定的提交,这将导致分离的 HEAD 状态。继续上一个场景,如果您检查主分支上的第一个提交,您将看到 HEAD 现在被分离。
在这种情况下,HEAD 不指向任何分支—它引用提交。
可能导致分离磁头状态的场景
你会发现自己处于一种超然的状态,主要是通过两种情况:
- 签出特定的安全哈希算法 1 (SHA-1)提交哈希
- 不先提取就签出到远程分支
我们已经演示过,如果您签出 SHA-1 提交散列,您将处于分离头状态。导致分离头的另一种情况是检查远程分支。如果您检出到只读的源(主)分支,您将处于分离的 HEAD 状态。
其他一些情况也可能导致头部分离。例如,检查一个特定的标签名或在任何给定的分支上添加^0
会导致分离的 HEAD 状态。
如何在分离的头中保存更改
如果你发现自己是一个超脱的头部状态,并且很快意识到,那么你可以通过检查之前的分支来快速恢复。但是,如果您错误地处于分离的 HEAD 状态,然后执行 commits over commits,该怎么办呢?如果您在分离的 HEAD 状态下提交,这是否意味着您的更改没有被保存?
一点也不。这只是意味着你目前没有附属于任何分支,因此,你的头是分离的。如果您想保留您在分离的 HEAD 状态下所做的更改,您可以通过三个简单的步骤来解决这个问题:创建一个新的分支,提交更改,以及合并更改。
创建新分支
要保存在分离的 HEAD 状态下提交的更改,首先需要创建一个新的分支。
从上面描述的场景继续,您创建一个名为temp-branch
的新分支。当您创建分支并检查到它时,头部不再分离。
提交更改
在签出到新的分支之后,您可以提交更改,Git 将保留这些更改。
合并更改
现在,您检查到您想要更改的分支。在这种情况下,您希望将更改合并到主分支。因此,您首先需要检查主分支,然后合并来自temp-branch
的更改并添加最终的提交消息。
通过这些简单的步骤,您已经成功地保存了您的更改并从 Git 分离头状态中恢复。
如何放弃分离头中的更改
如果要放弃分离的 HEAD 状态中的更改,只需签出到现有的或以前的分支。分离的 HEAD 状态上的提交不会影响您现有的分支,Git 会将它们存档。
下图显示了一种情况,在进入分离头状态后,您进行了两次不想保留的提交。然后,你去总分行结账。虚线圆圈表示这些提交不再是任何分支的一部分,Git 将删除它们。
注意,一旦 Git 删除了分离的 HEAD 状态提交,就没有办法恢复它们了。但是,如果它们没有被删除,您可以检查到 SHA-1 提交散列,创建一个分支,并将其合并到所需的分支以保留更改。
结论
Git 是一个有价值的开发工具,比 CVS 和 Subversion 等老版本工具更受欢迎。也就是说,掌握它可能会更加复杂和具有挑战性,有时会导致混乱的情况,例如分离的头部状态。
如果您发现自己处于分离的 HEAD 状态,请记住,您总是可以通过创建并检出到一个新的分支,然后提交并合并所需分支中的更改来保存您的更改。如果您不想保存更改,您可以简单地签出到任何分支,Git 会删除这些提交。
还有,Git 2.23 有一个新命令,git switch
。这不是一个新特性,而是git checkout
的替代命令,因此您可以在分支之间切换并创建一个新分支。要从一个分支切换到另一个分支,使用git switch branchName
创建一个新分支,然后使用git switch -c branchName
命令切换到该分支。
尽管在分离的 HEAD 状态下找到您的代码并不理想,但是您可以使用这些方法来移动或删除您的提交,并快速使您的项目回到正轨。
Github 集成目录和 CircleCI 移动支持- CircleCI
原文:https://circleci.com/blog/github-integrations-directory-and-circleci-mobile-support/
来自出版商的说明:您已经找到了我们的一些旧内容,这些内容可能已经过时和/或不正确。尝试在我们的文档或博客中搜索最新信息。
在移动 CI 和 CD 领域,这是非常忙碌的一周。随着 GH 集成目录的发布,对移动支持(包括 iOS 和 Android)的需求越来越大。以下是我们为满足 iOS 构建需求所做的工作。
我们在腾出空间
我们总是乐于欢迎新客户,我们工作的一部分是规划额外的容量,这种容量时好时坏。对于我们的 AWS 部署来说,为 Linux 添加额外的容量是非常简单的——只需敲击几下键盘(再用信用卡支付几次)。然而,增加 iOS 的容量需要更多的时间。这是因为我们的 iOS 构建运行在物理 Apple 硬件上,我们需要在数据中心购买、供应和安装这些硬件。我们已经在安装更多的苹果硬件,以支持更多的 iOS 版本,我们预计下周初将有足够的在线容量来支持我们第一次见到的大多数用户。
如何获得访问权限
由于我们根据具体情况启用 OS X 支持,请通过CircleCI.com上的聊天窗口联系我们,告知您希望运行构建的 GitHub 组织或帐户的名称,以及您每天将运行的构建的大致数量和您的 iOS 开发团队所在的时区。一旦我们有了这些信息,我们会尽最大努力尽快给你 iOS 版本。
等待是值得的
我们对待 iOS 构建的热情与对待 Linux 构建的热情是一样的——每个构建容器都是在构建开始之前创建的,并在所有命令完成后立即销毁,以确保构建的最大安全性和可靠性。在 iOS 容器中,我们预装了 Xcode 版本 6.3.1、6.4 和 7.0,我们还捆绑了 Homebrew 和cocoapods
等工具,以确保您拥有项目的所有依赖项,并在构建中正确配置。一旦您的组织启用了 iOS 测试版,您的构建将在几分钟内启动并运行。您可能在 Linux 版本中见过的其他特性,如加密的环境变量、部署和工件存储,也可用于 iOS 版本。
我们 Circle 对您的到来感到非常兴奋,我们期待为您提供优质服务!
如果您对这个或任何其他主题有任何疑问,请随时联系 sayhi@circleci.com。
(已经清除了 iOS 或 Android?这里有一些帮助你开始的文件。从 Ship.io 移动?我们已经整理了一份迁移文档来提供帮助)
集成 GitOps 和 DevOps:实现两者的优势
GitOps 已经成为一个时髦词。开发人员喜欢它,因为它将 DevOps 折叠到 Git 中,这是一个经常使用和熟悉的工具。使用一个工具来管理多个 DevOps 活动听起来很棒,而且对很多人都有帮助。事实是 GitOps 是有限制的。在本文中,我们将探索 DevOps 和 GitOps,比较它们的相似之处和不同之处,并研究它们的原理如何协同工作来支持您的软件开发目标。
DevOps 是什么?
DevOps 改变了我们处理和开发软件的方式。这是什么?DevOps 是一套促进开发和运营团队之间协作的工程哲学、工具和文化实践。这种协作减少了团队之间的摩擦,加速了软件开发生命周期,通过更快的反馈实现了更快的软件交付。DevOps 打破了传统软件开发团队中常见的孤岛。
组织经常将开发和操作团队合并成一个单位,在开发过程中一起工作。这个单元通常包含开发生命周期中的每个人,包括质量保证专家和安全分析师。每个人共同努力实现 DevOps 文化。他们实施实践并使用工具,在整个应用生命周期中促进持续集成和持续交付(CI/CD) 。
这些工具和技术自动化了构建、测试和部署应用程序等过程。作为代码的基础设施是另一个元素,我们将在本文后面讨论。
什么是 GitOps?
GitOps 借鉴了 DevOps 的一些思想,将 Git(版本控制系统)和 operations(软件开发的资源管理方面)结合起来。像 DevOps 一样,GitOps 使用基础设施的现有流程作为代码(IaC)、版本控制、代码审查和 CI/CD 管道。
在许多情况下,GitOps 扩展了现有的 DevOps 实践。通过代码部署基础架构消除了团队通常用来设置环境的点击式流程,从而缩短了上市时间。
这种方法还使用合并请求来降低部署糟糕的基础设施的风险。在将更改合并到主分支之前,至少还有一个人会对其进行检查。自动化部署和测试还减少了成本和应用程序停机时间,从而实现了更快的回滚。
GitOps 在 DevOps 中的传统角色
做得好的话,DevOps 打破了竖井思维,将团队聚集在一起,这样他们可以有效地为共同的目标而工作。GitOps 是 DevOps 的最佳实践,它共享诸如协作、持续改进和自动化等原则。很容易将 GitOps 工作流集成到积极使用的 DevOps 技术中。
许多 DevOps 团队已经在使用 Git 了。毕竟,它是世界上最流行的版本控制系统,GitOps 过程围绕着它。Git 允许团队通过编写声明性代码并将其推送到 repo,频繁而快速地试验新的基础设施和基础设施配置。如果更改破坏了基础设施或者没有按照预期的方式运行,或者如果您对更改不满意,Git history 可以恢复到以前的基础设施版本。
使用 GitOps 将基础设施作为代码进行管理
软件应用的进步已经导致许多软件开发过程的自动化。然而,基础设施自动化并没有得到同样的关注。在很大程度上,基础架构的实施和管理仍然是手动过程。像 Ansible 和 Terraform 这样的自动化工具提供了一个良好的开端,但它们不是端到端的解决方案。
IaC 使您能够使用声明性代码来管理和配置基础架构,而不是传统的、耗时的手动过程。与参数化相结合,IaC 允许您使用不同的设置将相同的服务多次部署到不同的环境中。
GitOps 通过充当管理和自动化基础设施的软件开发机制来提供帮助。
云原生开发的 GitOps 限制
GitOps 通过简化基础设施部署使软件开发团队受益。尽管 GitOps 的好处很吸引人,但它也有其局限性。GitOps 有几个不足之处:
- 无服务器基础设施
- 机密管理
- 自动化功能
无服务器基础设施
采用 GitOps 策略既昂贵又耗时。对于不希望管理部分或全部基础架构的团队来说,无服务器计算成为一种极具吸引力的选择。
无服务器计算提供了一种无需管理基础设施即可部署和执行软件的方式。云提供商会为您解决所有这些问题。
将基础设施管理的任务委托给像 AWS Lambda 或 Azure Functions 这样的云提供商会使 GitOps 过时。开发人员在使用这些功能时,会向云提供商提供一个功能(只是一段代码)。提供者执行该代码。开发人员的组织不需要 GitOps 工具或流程来提供或管理任何基础设施来运行代码。
机密管理
应用程序使用秘密进行身份验证和其他敏感的细节。用于连接数据库的字符串是秘密的一个例子。我们必须极其小心地对待这些秘密,以保护我们的软件和系统。
虽然 GitOps 将 Git 放在基础设施管理的中心,但是 Git 并不能帮助管理机密。在公共 Git repo 中保守秘密会使您的应用程序易受攻击。私人回购并没有更安全。所有回购的贡献者都可以看到秘密,这违背了访问管理和基于角色的访问控制(RBAC)的规则。
我们都喜欢 Git 的历史跟踪特性——这是我们使用 Git 的主要原因之一。然而,想想历史跟踪对你的秘密意味着什么。您可能会在某个时候决定从回购中删除这些秘密,但它们将永远存在于 Git 历史中。随着回购数量的增长,每个回购都必须管理自己的秘密。这对管理他们的团队来说是一个挑战。
自动化限制
合并和拉取请求的 Git 特性有助于确保我们不会合并和部署糟糕的代码。然而,这是一个需要人工干预的手动过程。它不太符合自动化的理念——这是 GitOps 的一个关键原则。
YAML 文件推动 IaC 部署。GitOps 方法将这些文件存储在 Git 存储库中,并在 YAML 文件发生变化时创建一个合并请求。当流程检查文件并将它们合并到主分支时,它会触发一个部署管道。
随着部署环境数量的增加,这种方法变得更加困难。每个环境都需要一个单独的存储库,因此管理合并请求变得越来越费力。
结论
GitOps 补充了现有的 DevOps 战略。使用 Git 这样的版本控制系统来自动化基础设施部署,实验变得更加容易,因为您可以恢复到工作状态。将 GitOps 集成到 DevOps 中很容易,因为它们使用类似的工具集。但是请记住,GitOps 就像任何其他流程一样,并不完美,也有自己的缺陷。
DevOps 和 GitOps 没有内聚性,也不应该紧密耦合。事实上,他们有共同的原则,这意味着他们可以很好地集成在一起,但他们并不需要对方。有 DevOps 文化的团队不需要使用 GitOps——没有 DevOps 文化的团队仍然可以!
实施 DevOps 和 GitOps 战略是一个旅程,CircleCI 可以帮助您和您的团队更快地实现目标。探索 CircleCI 提供的众多 DevOps 工具来支持您的 DevOps 和 GitOps 工作。
在 CircleCI - CircleCI 中启用 Go v1.11 的模块支持
Go v1.11 于 2018 年 8 月 24 日发布。有相当多的变化!虽然有几个变化我真的很喜欢,比如能够分配嵌套变量,但也有一些变化会影响你的 CircleCI 构建。
在版本中启用模块支持
CircleCI 上一个典型的 Go 项目的配置是这样开始的:
version: 2
jobs:
build:
docker:
- image: circleci/golang:1.10
working_directory: /go/src/github.com/my-org/my-repo
steps:
- checkout
简单地将 Docker 映像更改为circleci/golang:1.11
将而不是启用模块支持。相反,有两种不同的方法可供您使用:
- 将您的代码移出
GOPATH
- 将
GO111MODULE
环境变量设置为"on"
方法 1 -将代码移出 GOPATH
使用 Go v1.11 Docker 映像,通过将代码移动到GOPATH
之外的路径来启用模块支持。例如:
version: 2
jobs:
build:
docker:
- image: circleci/golang:1.11
working_directory: /my-app
steps:
- checkout
更好的是,除非你绝对需要指定一个working_directory
,否则我会把它完全从配置中去掉。当你省略它时,CircleCI 默认为~/project
,并且在你的配置中少了一行。这是我推荐的启用模块支持的方法:
version: 2
jobs:
build:
docker:
- image: circleci/golang:1.11
steps:
- checkout
方法 2 -使用 go 111 模块
如果您喜欢将项目代码保存在GOPATH
中,可以通过环境变量启用模块支持。这里有一个例子:
version: 2
jobs:
build:
docker:
- image: circleci/golang:1.11
environment:
GO111MODULE: "on"
working_directory: /go/src/github.com/my-org/my-repo
steps:
- checkout
注意用于包装"on"
的双引号。对于许多人来说,不使用引号会导致 YAML 将值解释为true
,而 Go 不接受这个值为有效值。
在存储库中启用模块支持
为了让 CircleCI 构建工作,您的存储库也必须构建为支持 Go 模块。关于这一点有很多要说的,你可以在 Go Wiki 上详细阅读。如果你的项目比副业项目大,我建议你通读一遍。下面是简短的版本。
准备您的代码:
go mod init
如果您来自另一种流行的 Go vendoring 方法,如 Dep,则可以跳过下一步。否则,需要执行以下步骤来创建一个完整的go.mod
文件:
go mod tidy
现在,将 mod 管理文件添加到 Git 是最后一步:
git add go.mod go.sum
git commit -m "Add Go module support."
git push
如果您之前没有使用依赖管理器,而只是使用go get
来获取包,那么现在您可以从 CircleCI 配置中删除它。
测试
有两种形式的go test
供你考虑:
go test ./... # Tests only the code in your current module, typically your repo.
go test all # This will test your code as well as direct and in-direct dependancies.
贮藏
使用 Go 模块时,缓存位置会发生变化。以下是恢复和保存缓存的方法:
- restore_cache:
keys:
- go-mod-v1-{{ checksum "go.sum" }}
# ...
- save_cache:
key: go-mod-v1-{{ checksum "go.sum" }}
paths:
- "/go/pkg/mod"
好运,地鼠们。😃
更多资源
使用 AWS 自动缩放组和 Terraform | CircleCI 正常关机
来自发布者的说明:此内容由 Devops 高级客户工程师本·范·豪登于 2020 年 9 月 3 日更新。
理论上,亚马逊的自动伸缩小组(ASG)是一种很好的伸缩方式。这个想法是,你给他们一个期望的能力,以及如何启动更多机器的知识,他们将完全自动旋转你的车队上下随着期望的能力变化。不幸的是,在实践中,有几个关键的原因,我们不能使用它们来管理我们的 CircleCI.com 舰队,其中最重要的是默认的 ASG 终止策略杀死实例太快。因为我们的实例正在为我们的客户运行构建,我们不能简单地立即杀死它们。我们必须等待所有构建完成,然后才能终止实例。
正常关机,在终止一个实例之前,您必须等待一些条件,这不是我们独有的问题。但这个问题的解决方式会因车队规模和使用模式的不同而不同。例如,我们使用一个定制系统来扩展我们的 CircleCI.com 车队,因为 CircleCI.com 的负载遵循一个很大程度上可预测的使用模式,该模式基于我们的客户在世界各地工作的时间,其中夹杂着一点随机性。ASG 提供的简单的基于度量的扩展策略不足以对此建模。
但是,随着circle ci Enterprise的发布,我们意识到,当我们的每个客户的车队规模和负载要求通常要简单得多时,要求他们发明自己的完全定制的扩展系统是没有意义的。因此,我们想看看是否有一种方法可以创建一个简单的解决方案,涵盖我们大多数客户的常见扩展模式,同时如果基础不够,还允许他们进行更多的定制。
CircleCI 1.x 解决方案
概括地说,我们的解决方案包括四个部分:
- 管理 EC2 实例的 ASG。
- 一个自动扩展生命周期挂钩在关闭实例时发布通知,并将服务器置于“终止:等待状态,并触发 SNS 通知。
- 触发 Lambda 函数实现生命周期钩子动作的 SNS 主题。
- Lambda 将通过指定节点上的 AWS SSM 执行“nomad node drain -enable”命令。这将确保将要终止的 nomad 客户端不会构建更多的作业。
- 给定的节点将被标记为
ineligible
,以防止新的作业排队,并且所有的作业将从该节点打包,以便优雅地终止。 - 一旦命令成功,该节点将被 ASG 完全终止。
我们使用 Terraform 管理我们的 CircleCI.com AWS 基础设施,并在我们向客户推荐的 CircleCI 企业脚本中使用。我们是它的超级粉丝,因为它允许我们以一种比 CloudFormation 更简洁、更不容易出错的方式用代码声明性地列出我们的基础设施。下面的资源将作为 terraform 示例列出,但是如果您想要手动构建它,或者使用 CloudFormation,这种方法仍然有效。如果你想亲自尝试的话,我们已经提供了完整的地形文件。
自动缩放组
我们不想为 CircleCI 企业客户自动化我们的手动扩展策略,而是希望提供现有最佳实践的挂钩。对于 AWS,这意味着自动扩展组。助理秘书长提供了很大的灵活性。最简单的形式是,它们充当非常基本的容错功能,如果任何一台机器停止工作,它们就会自动启动新的机器。它们还允许您附加一个扩展时间表以实现基于时间的简单扩展,或者附加一个扩展策略以实现基于指标的反应式扩展。出于这篇博文的目的,我们假设您已经有了一个名为nomad_clients_asg
的 ASG 设置。
自动扩展生命周期挂钩
但是,正如我们之前提到的,ASG 不会给你很长的时间来终止一个实例。对我们来说,我们的正常关闭必须等待构建完成后才能终止实例,这个过程可能需要半个小时或更长时间。因此,我们转向一个相对不为人知的 ASGs 附加物,生命周期挂钩。
生命周期挂钩允许我们在 ASG 执行某些操作时从 Amazon 获得通知。在这种情况下,我们关心的是autoscaling:EC2_INSTANCE_TERMINATING
,它告诉我们 ASG 何时试图终止一个实例。我们选择了 1 小时的heartbeat_timeout
和CONTINUE
的default_result
。由于我们的正常关机通常不到一个小时,这意味着如果出现问题,而我们在一个小时后仍在运行,亚马逊将强制终止我们。
resource "aws_autoscaling_lifecycle_hook" "graceful_shutdown_asg_hook" {
name = "graceful_shutdown_asg"
autoscaling_group_name = "${aws_autoscaling_group.nomad_clients_asg.name}"
default_result = "CONTINUE"
hearbeat_timeout = 3600
lifecycle_transition = "autoscaling:EC2_INSTANCE_TERMINATING"
notification_target_arn = "${aws_sns_topic.graceful_termination_topic.arn}"
role_arn = "${aws_iam_role.autoscaling_role.arn}"
}
亚马逊社交网络通知
您会注意到在上面的例子中,生命周期挂钩的notification_target_arn
是一个 SQS 队列。这是因为亚马逊需要某个地方来发送终止消息。我们没有编写自己的端点,而是决定让 Amazon 来维护需要为我们终止的实例的状态。
resource "aws_sns_queue" "graceful_termination_queue" {
name = "graceful_termination_queue"
}
SNS 主题本身的示例代码非常简单,但是您还需要创建一个 IAM 角色和相关联的策略,以允许生命周期挂钩发布到 SNS 主题(在上面的role_arn
小节中进行了配置)。
resource "aws_iam_role" "autoscaling_role" {
name = "autoscaling_role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "autoscaling.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
EOF
}
resource "aws_iam_role_policy" "lifecycle_hook_autoscaling_policy" {
name = "lifecycle_hook_autoscaling_policy"
role = "${aws_iam_role.autoscaling_role.id}"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Action": [
"sns:Publish",
],
"Resource": [
"*"
]
}
]
}
EOF
}
在这里使用 SNS 主题对我们来说是正确的解决方案,因为我们的架构允许多个工作人员使用关机通知。如果你的架构需要一个可以关闭任何追随者的领导者,因此我们只有一个消费者,那么你应该考虑在这里使用 SQS 队列(亚马逊的发布订阅服务)。
优雅的关机
唯一剩下的部分是来自队列的实际消耗,以及机器的正常关闭。根据您如何进行正常关机,您使用队列的解决方案可能与我们的非常不同。但是您仍然需要知道队列中通知的一些情况。
首先,当您第一次连接生命周期挂钩时,Amazon 会发送一个测试通知,以确保连接正常工作:
{
"AutoScalingGroupName":"example_asg",
"Service":"AWS Auto Scaling",
"Time":"2016-02-26T21:06:40.843Z",
"AccountId":"some-account-id",
"Event":"autoscaling:TEST_NOTIFICATION",
"RequestId":"some-request-id-1",
"AutoScalingGroupARN":"some-arn"
}
您可以安全地忽略消费者中的消息。
实际的关闭通知是您需要知道的唯一的另一部分数据,它们看起来像这样:
{
"AutoScalingGroupName":"example_asg",
"Service":"AWS Auto Scaling",
"Time":"2016-02-26T21:09:59.517Z",
"AccountId":"some-account-id",
"LifecycleTransition":"autoscaling:EC2_INSTANCE_TERMINATING",
"RequestId":"some-request-id-2",
"LifecycleActionToken":"some-token",
"EC2InstanceId":"i-nstanceId",
"LifecycleHookName":"graceful_shutdown_asg"
}
注: 这种特殊的解决方案仅适用于 CircleCI Enterprise 2.0。
如何使用这些通知完全取决于你。在我们的例子中,我们只是在客户可以定制的 Lambda 函数中添加了一个 Node.js 脚本运行器。我们这样做是因为我们想给我们的客户一些预打包的东西,并且易于配置。
AWS Lambda 函数和 SSM 代理文档
我们的 Lambda 函数利用 AWS Javascript SDK 来利用系统服务管理代理,并与指定的自动缩放组进行通信。AWS SSM 代理是亚马逊软件,可以在 EC2 实例上安装和配置,如果您使用我们的基本企业设置 terraform 脚本 CircleCI 利用亚马逊的 Linux AMIs,它将预安装 AWS SSM 代理。
为了继续使用我们的解决方案,您需要上传一个 SSM 文档,该文档允许您定义希望 System Manager 对您的 AWS 资源(在本例中为我们的 nomad 客户端)执行的操作。对于此解决方案,SSM 文档如下所示,它执行 nomad drain 命令,然后检查节点是否合格:
{
"schemaVersion": "1.2",
"description": "Draining Node",
"parameters":{
"nodename":{
"type":"String",
"description":"Specify the Node name to drain"
}
},
"runtimeConfig": {
"aws:runShellScript": {
"properties": [
{
"id": "0.aws:runShellScript",
"runCommand": [
"#!/bin/bash",
"nomad node drain -enable -self -y",
"isEligible=$(nomad node-status -self -json | jq '.SchedulingEligibility | contains (\"ineligible\")')",
"if (( ${isEligible} == true )) ; then exit 0 ; else exit 129; fi"
]
}
]
}
}
}
您可以将该文件保存为 document.json,并执行以下命令在 SSM 中创建它:
aws ssm create-document --content "file://drain-document.json" --name "CircleCiDrainNodes" --document-type "Command"
最后,您需要创建一个 Lambda 函数来处理生命周期挂钩。将 Lambda 代码下载到您的本地工作站,并安装代码依赖项。安装时,请确保您使用的是与 Lambda 相同的版本,并定制 Lambda 脚本以匹配您的环境。
压缩代码并创建一个 Lambda 函数(或者你可以参考我们的 Zip 文件这里)。
结论
长期以来,自动缩放组一直是管理缩放的最佳选择,因为它们在如何缩放方面提供了如此大的灵活性。此外,随着生命周期挂钩的增加,它们还为您提供了终止方式的灵活性,允许平稳关闭。
这意味着,当我们在寻找一种解决方案,让 CircleCI 企业客户能够以最少的运营团队开销扩展其车队时,带生命周期挂钩的 ASG 是一个很好的选择。他们提供了一个即插即用的解决方案,不仅能带来立竿见影的价值,还允许我们的客户在实际扩展车队的方式上进行高级定制。
在 Android 项目中使用 Gradle build 扫描
原文:https://circleci.com/blog/gradle-build-scans-for-android-projects-local-and-ci-builds/
一个构建扫描是一个 Android 构建的可共享的集中记录,它提供了对发生了什么及其原因的洞察。构建扫描的一些好处是:
- 他们帮助开发人员理解他们的构建每天是如何被使用的
- 它们为您提供每个开发人员和 CI 构建的深入的任务级数据、性能指标和可视化
- 开发人员可以使用构建扫描,通过发现和修复构建问题来显著提高构建速度和可靠性
- 他们通过允许开发人员共享构建扫描链接来指出问题或寻求帮助,从而创建协作
先决条件
要完成本教程,需要做一些事情:
- 对 Gradle 构建工具的基本理解
- 如何在 CircleCI 上建立 Android 项目的知识
- 了解 Android 构建流程。
如果在继续之前需要进一步阅读,请参考 Gradle 上的前一篇文章使用构建缓存加速您的 Android Gradle 构建。
构建应用程序
为了简洁起见,我们不会从头开始构建应用程序。相反,您将在一个初始项目的基础上进行构建。点击或git clone https://github.com/CIRCLECI-GWP/circle-notes.git
下载启动项目。我们将使用构建扫描文档。
步骤:
- 一旦本地有了项目,就在 Android Studio 中打开它。如果出现提示,在同步 Android SDKs 对话框中点击确定。
- 点击 1 并确认 2 被选中。这意味着已经安装了 API 级别 28。如果不是,点击复选框,然后应用和确定。否则,点击确定。
- 点击 Android Studio 上的运行按钮。
- 模拟器将启动,应用程序将运行。
</blog/media/2020-07-19-circle-notes.mp4>
正在设置
首先,我们将应用 Gradle Enterprise Gradle 插件。因为我们的项目使用 Gradle 版本5.4.1
,我们将使用com.gradle.build-scan
作为插件 ID。
插件必须在项目的build.gradle
文件中应用。
// TODO 1: Add Gradle Enterprise Gradle Plugin.
plugins {
id "com.gradle.build-scan" version "3.3.4"
}
// TODO 2: Add Gradle Enterprise Configuration.
gradleEnterprise {
}
注意 : 在本教程剩余部分的代码片段和截图中,我已经删除了‘TODO’行。
连接到 scans.gradle.com
因为我们没有设置 Gradle Enterprise 服务器,我们的构建扫描将发布到scans.gradle.com
。
您需要同意 https://gradle.com/terms-of-service.的服务条款(TOS)。您可以通过将以下内容添加到您的版本中来同意 TOS:
plugins {
id "com.gradle.build-scan" version "3.3.4"
}
gradleEnterprise {
buildScan {
// Connecting to scans.gradle.com by agreeing to the terms of service
termsOfServiceUrl = "https://gradle.com/terms-of-service"
termsOfServiceAgree = "yes"
}
}
注意 : 不同意您的构建中的 TOS 意味着每次您试图将构建扫描发布到scans.gradle.com
时,系统都会提示您这么做。
控制何时发布构建扫描
事实证明,在您应用插件后,构建扫描不会自动发布。但是,对于本教程,我们希望发布每个构建。我们可以通过使用publishAlways()
指令来做到这一点:
plugins {
id "com.gradle.build-scan" version "3.3.4"
}
gradleEnterprise {
// configuration
buildScan {
// Connecting to scans.gradle.com by agreeing to the terms of service
termsOfServiceUrl = "https://gradle.com/terms-of-service"
termsOfServiceAgree = "yes"
// Publishing a build scan for every build execution
publishAlways()
}
}
确保在对build.gradle
文件进行更改后同步项目。
生成本地生成扫描
要生成本地构建扫描,请在 Android Studio CLI 中运行以下 gradle 任务:
./gradlew assembleDebug --scan
在命令后添加--scan
会发布按需扫描。
在assemble Gradle
任务完成运行后,您将在 CLI 中看到构建扫描链接输出。
这个项目使用 JDK8 运行良好。如果你运行的是 JDK 10 或以上版本,可能需要在 app 层面对这三个文件:gradle/wrappper/gradle-wrapper.properties
、build.gradle
、settings.gradle
做一些修改。
您可以在本教程中使用一个例子: Pull Request 。这些更改确保您的目标是最新版本的 gradle (6.7),并更新构建扫描插件以与 gradle 6.7 一起工作。
单击链接打开构建扫描。
输入您的电子邮件以激活构建扫描。扫描将发送到您的电子邮件收件箱。
注意 : 选中记住我复选框,你的电子邮件地址可以保存 90 天。
恭喜你!您已经生成了本地生成扫描。
生成 CI 构建扫描
生成持续集成(CI)构建扫描取决于您如何设置您的构建。在这部分教程中,我将向您展示如何使用circle-notes
项目设置 CI 构建扫描。使用这个项目,每当我们向主分支提交变更时,就会触发构建扫描。无论构建是失败还是成功,都会触发构建。
本教程的 starter 项目中已经提供了config.yml
文件。您需要在 Circle CI 上设置此项目,以触发 CI 构建。
如果你是第一次这样做,点击设置项目,然后使用现有配置。然后点击开始建造。
我们所做的任何更改都会触发一个工作流,其中运行unit test
和lint
作业。
点击 build 查看详情。
当您在浏览器中打开构建扫描链接时,系统会提示您激活构建扫描。(就像本地生成的一样。)当您激活它时,您应该会看到属于 lint 和单元测试任务的构建扫描。
恭喜你!您已经生成了 CI 构建扫描。
如何使用构建扫描
在这一节中,我将强调您可以使用构建扫描做的几件事情。
1.共享控制台日志
生成扫描包括由生成产生的控制台输出。该版本使用的许多工具(如编译器)会将诊断信息写入控制台日志。
使用左侧导航菜单访问控制台日志部分。点按任意线条以高亮显示它,或者按住 shift 键点按以高亮显示线条块。
您会注意到浏览器的当前位置已经更新。通过与同事共享该 URL,您可以将他们引向您希望他们看到的确切控制台输出。构建扫描的许多方面都可以直接链接,使共享和协作更加容易。
2.查看和共享测试执行结果
测试是软件开发的基石。构建扫描可视化测试结果,包括测试持续时间、日志输出和结果。
使用左侧导航菜单访问测试部分。单击任何失败的测试,查看控制台输出和错误跟踪。
构建扫描的链接使得开发人员几乎可以毫不费力地与他们的团队和其他同事共享本地构建的测试结果。这种简单的协作使得解决测试失败更加有效和快速。
3.分析构建性能
构建扫描的一个主要好处是它们提供了对构建性能的广泛洞察。许多构建在不同的机器上会有不同的表现。深入的性能洞察让用户能够优化构建的每个角落。
从左侧导航菜单中点击性能。
性能的每个方面都有一个选项卡。第一个构建选项卡显示了高级构建时间细分和内存信息。
配置选项卡分解了在构建中配置项目所花费的时间。该细分交互地突出了构建期间使用的最慢的脚本、插件和生命周期回调。优化这些速度较慢的物品,使你的构建速度更快。
任务执行选项卡根据结果对构建任务进行分组,并提供它们的简明分类。使用这个高级视图来理解特定构建的增量构建和构建缓存覆盖率。专用的时间线部分(可从左侧导航菜单中获得)提供了可视化任务执行的另一个视图。单击任务名称以获取更多详细信息。时间线部分清楚地显示了构建的并行利用。
网络活动标签列出了构建过程中产生的网络请求,可以用来识别缓慢的依赖库或特别麻烦的请求。
4.了解您的依赖关系
每次构建扫描都提供了在构建期间解析的每个依赖项配置的交互式可视化。您可以按名称或解决方法的类型搜索版本中所有项目的依赖项。
结论
本教程完成!您学习了如何:
- 生成本地和 CI 构建扫描
- 在线查看版本扫描信息
- 创建一个脚本,为所有生成启用生成扫描
使用您所学到的知识来优化构建,并提高团队的生产力和绩效。
Taracha 是一个创造者,他的使命是帮助公司用最简单的方式解决复杂的问题。他关心寻找他热爱的愿景&事业,并利用技术帮助这些公司解决他们的挑战。
他有超过 6 年的本地移动应用程序开发经验&大约 4 年的 web 应用程序开发经验。
他目前是 Premise Data 的高级软件工程师,负责新产品功能的开发和部署,对开发人员生产力工程领域特别感兴趣。
针对 CI/CD 管道使用 Docker 的指南
原文:https://circleci.com/blog/guide-to-using-docker-for-your-ci-cd-pipelines/
Docker 是什么?
Docker 是开发人员和系统管理员使用容器开发、部署和运行应用程序的平台。
Docker 也被称为应用程序打包工具。这意味着可以将启用的应用程序配置并打包到 Docker 映像中,该映像可用于生成运行应用程序实例的 Docker 容器。它提供了许多好处,包括运行时环境隔离、代码一致性和可移植性。
Docker 容器可以在任何支持 Docker 引擎的操作系统上运行。在 CircleCI 和 Docker:你需要知道的事情中找到更多信息
什么是码头集装箱?
Docker 容器旨在隔离和大规模运行应用程序。它们允许简化应用程序的管理和实现。
Docker 容器是基于并衍生自 Docker 图像的对象。Docker 图像是模板,就像饼干切割器一样。曲奇切片机使您能够快速、一致地从面团中生产出一块块曲奇。就像 cookie 是通过 cookie cutter 的类型来区分形状一样,Docker 映像决定了它们所创建的 Docker 容器的规格。
在 CircleCI 上构建 Docker 图像
Docker 映像包含构建 Docker 容器的指令,因此特定于希望在容器中运行的应用程序类型。在 CircleCI 上构建 Docker 映像被简化了,因为 CircleCI 原生支持 Docker。这允许在 Docker 中构建 Docker 和多级 Docker 构建。CircleCI 支持使用setup_remote_docker:
键在 CI/CD 管道中构建 Docker 映像,从而能够从 Docker executor 作业中构建、运行和推送映像到 Docker 注册表。
CircleCI 通过 Dockerfile 向导使构建定制 Docker 映像变得更加容易。此外,看看这些优化 Docker 构建的技巧,帮助你开始优化你的 Docker 映像开发和构建过程。不是每个人都想构建自定义图像。创建一个定制的 Docker 映像来运行您的 CI 构建不是一项简单的任务。在需要安装大量软件包、需要编译源代码或通过慢速连接下载的情况下,这是您自己的自定义 Docker 映像大放异彩的最佳时机。
使用 Docker 图像
Docker 实现了持续集成和交付最强大的好处:独立构建和测试。用 Docker 构建 CI/CD 管道利用干净的容器来消除本地应用程序开发中出现的任何依赖问题。这个过程需要将你的申请归档。
归档应用程序
在 Docker 中包装应用程序是加强正确的依赖关系和操作系统的强大方法。它还需要额外的知识来正确地配置和打包容器映像。有几个工具可以帮助你整理你的应用程序。例如,你可以用 Jib 对 Java 应用程序进行 Dockerize。使用 Dockerfile 对应用程序进行 Dockerfile 化是最常见的方式。以下是一些使用 Dockerfile 对应用程序进行 Dockerizing 的不同示例:
发布 Docker 图像
还有很多 Docker 注册中心 : Docker Hub、AWS 弹性容器注册中心、Azure 容器注册中心、Google 容器注册中心等等。CircleCI 拥有部署 orb,可以帮助设置这些服务的部署。一个 orb 是一个可重用的 YAML 配置包,它将重复的配置压缩成一行代码。例如,您可以使用 AWS ECR orb 自动将私有 Docker 映像部署到 AWS ECR 。
Docker 图像的安全性
使用公开可用的 Docker 镜像涉及到减轻与 OSS 软件相关的风险类型。因此,扫描图像对于发现漏洞至关重要。图像扫描可以在 orbs 的帮助下进行,以简化扫描工具的集成,如 Anchore 、 AquaSec 和 Snyk 。例如,请参见使用 Anchore 将容器安全扫描添加到 CircleCI 管道或使用 Twistlock orb 将容器图像扫描集成到 CircleCI 构建中或 CircleCI 工作流中的使用 Snyk 安全。
测试码头集装箱
测试 Docker 容器是任何 CI/CD 管道的关键部分。大多数团队在应用程序级测试方面做得很好,并且有大量的框架(包括 JUnit 和 RSpec)来支持它。但是服务器级测试——服务器配置和服务的验证——经常被忽略。要了解如何针对自定义 Docker 映像执行测试,请参见使用 CircleCI 和 Goss 测试 Docker 映像。
我应该使用 Docker 吗?
是的,您应该使用 Docker,因为它支持隔离测试。测试驱动开发是 CI/CD 的重要组成部分。经过良好测试的应用程序更有可能顺利交付给用户。对于部署应用的完全自动化的 CI/CD 管道,开发人员需要相信测试结果揭示了用户可能遇到的任何问题。我们进行隔离测试,以消除本地开发机器的影响。独立构建和测试的好处是,您可以放心地将自动通过所有测试的代码交付给您的用户。
Docker 和 CircleCI
CircleCI 上的 Docker 是一流的体验。CircleCI 为各种编程语言和一些数据库维护了一批 Docker 映像,称为便利映像。这些映像专门设计为在持续集成(CI)环境中运行良好。它们的存在是为了给用户提供一个快速方便的起点。我们还拥有强大的高级功能,如 Docker 层缓存,以保持您的 Docker 映像构建尽可能快。
现在就开始使用 CircleCI 上的 Docker:
Docker 和工作流一起为构建过程增加了功能和定制。通过工作流,您的 VCS 提供商(例如 GitHub)将获得一个状态列表,每个作业一个状态。这样,更容易一眼看出故障发生在哪里,并且您可以直接导航到失败的作业。使用工作流保持快速高效的构建。
在 CircleCI 上构建 Docker 图像
为了帮助您最大限度地构建 Docker 图像,CircleCI 提供了对 Docker 层缓存的支持。CircleCI 将尝试重用在之前的作业或工作流程中构建的任何 Docker 图像(层)。在之前的作业中构建的每个未更改的层都可以在远程环境中访问。然而,有些情况下,即使配置指定了docker_layer_caching: true
,您的作业也将在干净的环境中运行。这些情况涉及到为依赖于相同环境的相同项目运行许多并行作业。
有关更多信息,请查看配置最佳实践:Docker 层缓存和 Docker 层缓存文档。
2020 年 Hacktoberfest 即将到来:用 CircleCI orbs - CircleCI 庆祝开源
原文:https://circleci.com/blog/hacktoberfest-2020-is-upon-us-celebrate-open-source-with-circleci-orbs/
每年十月,随着树叶颜色的变化,天气变冷(或者如果你在南半球,情况正好相反),一个全球性的现象开始了:Hacktoberfest!
Hacktoberfest 是一个为期一个月的开源庆典,由 DigitalOcean 于 2014 年发起,旨在鼓励对开源社区的了解和参与。仅在 2019 年,就有超过483,000 个拉请求在154,000 个存储库上开放,参与者来自 142 个国家——这是该社区真正令人印象深刻的成就。
在 CircleCI,我们一直坚信开源,以及它能给组织带来的价值。我们在 CircleCI 上支持开源项目有着悠久的历史,许多最大的开源项目都在他们的管道中使用 CircleCI。
对于今年的活动,任何符合 Hacktoberfest 核心要求的人(至少有 4 个有效的 PRs 提交给开源项目)都将获得活动赠品,包括支持赞助商提供的 Hacktoberfest t 恤和贴纸。
啤酒节:用 CircleCI 圆球破解 OSS
去年,我们推出了第一个“T0”啤酒节,以配合黑客啤酒节。啤酒节鼓励社区了解 CircleCI orbs :可重用的 YAML 配置包,将重复的配置行压缩成一行代码。orb 帮助您打包、运输和重用代码。我们今年将重访啤酒节,以帮助更多的开发者了解 orbs 和 Hacktoberfest。您还有机会获得我们独特的限量版奖品,让您的奖金翻倍。
如何参与
今年有几种方法可以参与进来。要参加 Hacktoberfest,向 DigitalOcean 注册,并在整个 10 月提交 4 份符合其页面上列出的规格的 PRs。作为奖励,你可以接受 Hacktoberfest 的奖品,或者捐款种一棵树。要参加 CircleCI 啤酒节,您有以下几种选择。我们希望你为 CircleCI orbs 做贡献,完成挑战!
挑战:
挑战 1
创建一个 PR,以“啤酒节”为标签,在现有的 CircleCI 配置中包含 orb 的使用,并使该 PR 被接受或合并。对其他 CircleCI 回购的有效贡献,如 Docs,也可以考虑。
奖品:
1-3 名 PRs 领取贴纸包 4 名 PRs 领取贴纸和 t 恤
挑战 2:
使用 orb 开发工具包开发并发布一个 Orb。确保你的 orb 解决了其他开发者可能面临的挑战。
奖品:
贴纸包 t 恤限量版啤酒节徽章
完成上述挑战后,填写此表格即可获得奖品。10 月份结束后,我们将处理所有提交的材料,核实它们,并让您知道如何申请您的特殊 CircleCI 奖品。我们非常兴奋地看到所有对开源的贡献和我们今年将创建的 orb!
请务必参加我们社区论坛上的啤酒节讨论,了解想法、常见问题,并提出任何问题。你也可以通过#黑客啤酒节和#啤酒节标签关注 Twitter 上的对话!
体验研究| CircleCI
原文:https://circleci.com/blog/help-shape-the-future-of-circleci/
今天我们推出了 CircleCI 的研究页面。我们相信 CircleCI 与软件社区的合作设计。我们正在组建一个开发团队,他们将积极参与我们的设计过程。如果您注册,您将看到新的产品领域,成为我们开发新功能的一部分,并改进我们的核心产品。
我们为什么要这样做?
CircleCI 是一个元软件工程组织。我们想了很多关于我们的内部过程如何塑造我们创造的工具。而且,由于有自知之明,我们知道我们所处的环境与组织之外的环境极其不同。研究团队的任务是为所有软件团队建立同理心,并根据我们对他们需求的理解做出深思熟虑的设计决策。
我们还有哪些获得反馈的途径?
我们的参与式设计方法包括使用讨论论坛就平台如何工作进行对话,使用创意对特定功能进行投票,我们与各种各样的人一起进行特定的定性研究,以找出特定的设计难题。例如,在我们推出对 Windows 的支持之前,我们与用户一起测试了 Windows 映像,我们观察了许多人设置 CircleCI 管道的过程,我们描述了倡导将 CircleCI 作为一种工具是什么样的。
我们之前在做什么?
在我们推出这个页面之前,研究、设计和产品团队正在联系个人,希望他们相信我们没有恶意,我们对他们的时间有一个计划,他们能够影响产品的方向。我们会检查人们可以给出反馈的许多位置,并简单地希望我们在给他们发送冷冰冰的电子邮件时没有打扰他们。这并不总是一个顺利的过程,因为有时我们的研究只是部分地与人们在我们的 NPS 响应调查、讨论或 AHA 想法中发布的内容相关。我们现在的目标是提供一致的体验,让您了解我们如何使用您的数据(剧透:仅用于设计目的),了解更多关于我们的流程,如果您有色盲,请与我们分享,这样我们就可以确保我们的设计具有可访问性。
研究团队帮助设计平台的所有部分,因此您将有很多潜在的领域可以做出贡献。设计的重点是 UI,但它也关注错误消息、CLI 中包含的选项以及整体的合意性和功能性。注册成为我们开发流程的一部分,从今天开始影响 CircleCI 的未来!
如何解决 Clojure | CircleCI 中的一个主要日志问题
原文:https://circleci.com/blog/how-a-simple-logging-problem-turned-into-a-bear-trap-lessons-learned/
“开发人员被复杂性所吸引,就像飞蛾扑火一样,结果往往是一样的。解谜很好玩,开发者是解决问题的人。谁不喜欢匆忙解决一些极其复杂的问题呢?然而,在大规模软件中,在保留基本复杂性的解决方案的同时消除偶然的复杂性是具有挑战性的。”尼尔·福特
我用 Clojure 编码已经快 4 年了。我在 Clojure 中与登录斗争了将近 4 年。这并不是 Clojure 一个人的责任,但这似乎是一个经常遭受 Lisp 诅咒的问题。
在过去的一年里,当我在一个绿色的领域工作的时候(也就是,建筑背景),我再次遇到了一个伐木领域的“简单”问题……那就是我们吐出了我们所有的秘密。考虑到这可能足以阻止公开发布它,我的团队花了一些时间来深入挖掘,并追捕将我们的所有请求都写给stdout
的错误类。
牦牛毛:做一些与你真正目标无关的事情。
许多牦牛后来剃光了毛发,我们发现自己在思考我们在 CircleCI 想要从伐木中得到什么的本质。我们知道这个问题有很多层面,但我们也知道我们可以把它变得更好。然而,一旦我们戳中了它,我们发现它很难逃脱。就像飞蛾扑火,或是被困在陷阱里的熊。
熊陷阱:一个一旦戳中,就有咬人倾向,难以逃脱的问题。通常情况下,这些问题你知道你可以做得更好,但当你深入研究时,你会发现这些问题有很多层面,其中包括你的同胞。
下面是 CircleCI 最近的“熊陷阱经验”案例研究:登录 Clojure 应用程序。我们所有的代码都可以在这里找到。
日志记录的问题
CircleCI 的日志记录基础设施有很多吸引人的地方:
- 分布式体系结构
- 分布式团队
- 每天执行超过 40 万个外来代码实例(可能是您的代码!)
- Clojure 库
- 维护云、企业、测试 CI、开发和个人开发人员环境
为了做到这一切,我们依靠一些技术:
- Clojure:我们选择的主要语言
- Kubernetes :服务编排等。
- 用于内部服务通信的 gRPC
- PostgreSQL 用于长期存储
- 用于加密和轮换客户端数据的保险库
所有这些因素加在一起会导致不小的问题。
难以减轻的错误
没有什么比看到“AKIA……”出现在你的日志中更好的了。或者可能更好:“{'cookies' ['password:guest ',…]”等。
不管我们喜不喜欢,我们都是人。当你在一家像我们这样规模的公司工作时,与我们在所有不同地方的人一起工作,同时使用可爱的传统整体产品和小巧的新型微服务,就会出现错误。
通过 gRPC,我们的上下文服务记录了所有转储到其中的环境变量,我们知道应该对注销凭证采取预防措施。为了实现这一目标,团队建立了伐木危险预防。这最终归结为代码中几个简单的基于正则表达式的过滤器,可以<<REDACTED>>
任何可能相关的东西。
我们希望确保最终使用我们工具的人能够从中受益,并获得更大的回报。我们不想强制执行“更好的编码实践”或其他此类形式的羞辱新人的行为,我们只想让工具变得更好。套用这个比喻,试着给人们胡萝卜而不是大棒。
我们写了测试。我们验证了它的工作原理。在我们的内部测试中,我们看到我们所有的凭证仍然被记录。
由于这些过滤器没有在运行 Clojure 应用程序的 JVM 和聚合 stdout 的容器之间实现,因此我们需要确保我们的代码库正在查看所有的日志记录语句。不出所料,他们没有。
大约 5 种不同的日志记录框架(全部同时运行)
运行在 JVM 中的 Clojure 可以访问 Java 库和生态系统的巨大财富。像 HTTP 上的通信或加密之类的东西不需要完整地编写,因为其他人已经花时间为您提供了这些内容。这通常被认为是应该使用 Clojure 的主要原因之一。它是功能性的,适度的。
虽然 Java 社区在很多方面值得称赞(向后兼容性、Apache 等)。),日志可能不在其中。既然这在 Java-land 是个问题,在 Clojure 也是个问题。
我们在我们的代码库中发现有 6 个框架写给stdout
:
有些人会注意到 LogBack 不在这里。幸运的是,这不是我们发现注销的框架之一,但它是我们后来添加的一个(阅读下文)。
最终,我们希望所有这些都只通过一个记录器。我们希望能够简化我们的问题,缩小我们问题空间的范围。与其把你的整条腿伸进陷阱,为什么不只是一个脚趾呢?
我们当时的决定是音色。虽然从一个给定的记录器到音色的直接“桥接”输出对于上面的许多来说是不存在的,但是我们不需要它们,因为几乎它们中的每一个都有将其所有输出转发到 SLF4J 的方法。Clojure。工具。测井是最有可能是 已经在使用我们通过 SLF4J 输送的测井仪。由于 SLF4J 有一个巨大的音色桥梁,我们完成了!
也就是说,所有 java-land 的日志被转发到 SLF4J,然后我们将 SLF4J 正在做的所有日志发送到 Timbre。详情如下。
去 SLF4J
https://www.slf4j.org/legacy.html. SLF4J 在其网站上提供了一个很好的“处理遗留 API”自述文件:使用这个,你可以通过 SLF4J 谈论大多数事情。
虽然上面的大多数只需要在类路径中包含一些 jar,但是还有一些需要做更多的工作:
所以我们认为自己很聪明。然而,使用和索引任意日志条目不是一件小事,CircleCI 已经…
大量的日志
我们别无选择。我们每天生成大约 3 亿行日志。这是 1.5T。使用这些数据有多种形式:我们的安全团队依靠这些来审计客户的构建,我们的运营团队依靠这些来追踪比特币矿工,我们的开发人员依靠这些来进行监控/观察。如此多的人依靠这些日志来记录如此多不同的信息,结果是产生了大量的数据。通常,我们有专门的 prs 来寻找不再使用的日志行,以减少我们所携带的数据负载。
为了让我们所有人都能够从中获得我们需要的功能,我们必须解决许多问题,尤其是时区、不同的部署以及每个用例的专业领域。
因此,虽然存在像 Logstash 这样的工具,并且您可以很容易地添加“grok 过滤器”来解析日志行之外的字段,但是协调确保所有这些不同的过滤器仍然工作需要很多麻烦。
或者,您可以使用 JSON 作为传输工具。
我们不希望在我们的云和服务器产品中(或者在每个人的个人机器上)都处理这个问题,我们选择将消息作为 JSON 直接传输到 Logstash。有效载荷中出现的新字段被自动索引,时间戳“正常工作”。
最棒的是,有了结构化数据,编写单元测试变得轻而易举…
可测试日志记录
这一节很短,但以上都是可测试的。
Clojure Tools Logging 通过使用协议和接口在可测试性方面做了出色的工作,允许开发人员编写一个接收所有消息的记录器的假/模拟/存根实现。
音色与附加器有相似之处。对于我们的用例,我们能够注册一个测试 appender 并检查将要被记录的语句。
将测试作为一项需求来构建我们的工具是我们可能做过的最好的事情之一。之前已经说过无数次了,但是尽早测试,经常测试。分布式团队的协调是很重要的。如果你关心什么,你最好写一个测试。
在你做任何改变之前设置测试。如果别人替你写了测试,那就偷出来。如果别人为你窃取了适用的测试数据,那就把它也偷走吧!测试让你成为你自己工作的早期消费者,并让你在别人试图使用你的解决方案时感到痛苦。
释放
自行车脱落:辩论容易抓住的、无关紧要的项目,而不是问题的实质。
在将上述所有内容整合到我们的几个服务中,并且有了好运气之后,我们决定让团队的其他成员也参与进来。“测试版”的早期反馈过于积极。简单的设置,固执己见的配置,以及没有永远不会使用的旋钮和开关被吹捧为其最大的卖点。然而,内部版本几乎立刻就遇到了许多问题…
- 为什么我们要用音色,难道不应该用 X/Y/Z 来代替吗?
- 为什么要把这个烤成微服务框架?难道你不知道框架是魔鬼的作品吗?这不应该是一个独立的库吗?
- 我要做我自己的东西。
好心没好报,共享软件就是这样一种罪。作为开发人员,很容易将外部输入视为无知的感觉。但是,请记住反馈在构思生命周期中至关重要。这是我们改进和进步的方式。
第二波
大约在日志工作“完成”3 个月后,我们意识到我们需要更积极地思考常见事物应该如何在我们的生态系统中工作。我们希望给开发者必要的空间,让他们在这些问题上进行深思熟虑,所以 CircleCI 组建了一个团队,致力于在跨团队关注的领域开发工具。这个团队到目前为止工作得非常好(尽管我们确实怀念在 SRE 把东西扔过墙的日子)。
现在,团队正在发布日志工作,这似乎是一个突出那些没有成功的事情的好时机:
采用足迹更小
虽然 Clojure 社区中许多人对框架概念的反应本身就很可笑,但是希望简单的问题有简单的解决方案并不可笑。
采用并随后必须支持一个服务框架来“解决日志记录”是荒谬的。试图快速解决我们最初的问题最终混淆了我们解决方案的范围。相反,我们将我们的日志解决方案移到了它自己的库中。
*回想起来,将我们所有的工作放在我们预先存在的回购中使得开发周期变得很快,但是采用周期变得很慢。
在这些力量之间找到平衡是非常棘手的,也是我们一直努力解决的问题。
对于那些好奇的人,我之前在这里写过我们的“服务工具”框架。我们背板团队的第一个目标是将我们的“微服务框架”分解为“微服务机箱”,以使采用变得简单和渐进。希望是因为团队需要更多的与第三方服务(滚动条,Postgres 等)的集成。),他们可以抓住一个现成的机箱,毫不费力地将其安装到位。与他们自己构建相比,这将为他们提供更多的好处,并且添加它的开销将会很小。简单的问题,简单的解决方案,渐进的改变。
基于正则表达式的危险预防
该团队发现,编写过滤器来删除秘密内容很麻烦,而且肯定不能保证捕捉到所有内容。相反,他们的解决方案将预防的动力放在那些首先引入安全媒介的人身上。如果一个新值被认为是秘密的,它将有一个没有.toString
方法的特殊类型。相反,当.toString
被调用时,WARNING:REDACTED
将被返回。现在,使用这些秘密的人将不得不经历重重困难才能偶然记录一些东西。
(defprotocol SecretAccess
(danger [this]))
(defrecord SecretWrapper
[secret]
SecretAccess
(danger [this] secret)
Object
(toString [this] "<<REDACTED>>"))
(def x (SecretWrapper. "AKIAIOSFODNN7DAMNIT"))
x
=> #user.SecretWrapper{:secret "AKIAIOSFODNN7DAMNIT"}
(log/info x)
<<REDACTED>>
=> nil
这是在我们的编程中积极主动和被动反应之间的微妙区别。被动是在问题已经发生后再去处理它。主动是利用能力从一开始就防止问题发生。最终,我们期望这里会有更多的迭代,我们将最终得到两者的结合。
使用 Clojure 定义日志配置
虽然 Timbre 仍然是 CircleCI 的许多开发人员在未来的项目中用来登录的工具,但它在 Clojure 中的配置最终被视为前进的障碍。因为没有本机名称空间过滤,所以会传递更多不必要的日志消息,稍后再进行过滤。
目前,我们在一些共享服务容器中使用 LogBack 和一些嵌入式 XML 配置文件。最终开发人员无需进行配置,控制更加精细。
快乐黑客
发现小问题并逐步改善它们是一项神圣的工作。这也常常出乎意料的困难。我们希望不断反思我们是如何工作的,以及我们为什么做出决策,这将有助于我们在未来避免熊市陷阱。
总结一下上面关于熊市陷阱的知识:
- 尽早发现不同的观点和意见,将开发者的评论编织到构思生命周期中
- 奖励使用你代码的人,不要增加进入的门槛
- 试着简化你的问题,同时解决一些有意义的事情
- 协调一个分布式团队并不简单,试着自动化它(我们在 CircleICI 使用持续集成和测试,我知道这很令人震惊)
- 平衡您的开发周期时间和您的采用周期时间
一如既往,黑客快乐!*
并行测试-测试分割-优化的 CI/CD | CircleCI
今天版本的 XKCD 的“我的代码正在编译”漫画是“我的测试正在运行”。工程师是一种昂贵的资源,如果他们不得不等待很长时间来运行他们的测试,就像他们不得不等待很长时间来编译他们的代码一样,这也是一种资源浪费。在 Bolt ,我们使用 CircleCI 作为我们的持续集成 (CI)工具,我们一直在努力使我们的测试套件更快、更容易使用、更有用。这篇文章解释了我们如何减少 CI &集成测试管道所需的时间和配置复杂性,并强调了我们在这个过程中学到的东西。
我们如何在博尔特测试
我们在 Bolt 使用两种类型的测试工作流程。第一个是针对每个 PR 和每个 master 提交运行的单元测试。第二个是集成测试,在每次部署后针对我们的每个环境运行。前者很少是不可靠的:如果他们失败了,很可能需要调查。后者是浏览器自动化测试,本质上是不可靠的。让我们面对现实吧,在进行浏览器自动化测试时,我们总是在玩打地鼠游戏。即使您设法稳定了现有的测试,您的新测试也必定会引入更多的混乱。在 Bolt,我们对两种类型的测试都采用了不同的优化策略,以使两种测试都更有用。
CI 测试改进:测试时间减少 3 倍
由于 CI 测试针对每个 PR 运行,我们希望能够让开发人员尽快知道哪个(如果有的话)测试失败了。我们评估了我们的 CI 工作流,发现我们的构建管道后端大约需要 15 分钟,前端大约需要 20 分钟。我们知道我们可以做得更好。
基于运行时的并行测试
我们注意到的第一件事是,我们已经基于服务对 Golang 包的测试进行了逻辑分片。这意味着一些较小的服务在 2 分钟内完成测试,而较大的服务需要将近 16 分钟。在 CircleCI 的并行和基于时间的分割的帮助下,我们能够平衡碎片,使其花费大致相同的时间。circle ci 命令的这个片段展示了我们如何拆分我们所有的 Go 包:
commands:
make-check:
description: Runs tests
steps:
- restore_cache:
keys:
- go-mod-1-13-v1-{{ checksum "go.mod" }}-{{ checksum "go.sum" }}
- go-mod-1-13-v1-{{ checksum "go.mod" }}
- go-mod-1-13-v1-
- run:
name: Go tests for hail
shell: /bin/bash
command: |
set -e
cd /home/circleci/project/
# Improve sharding: https://github.com/golang/go/issues/33527
PACKAGES="$(go list ./... | circleci tests split --split-by=timings --timings-type=classname)"
export PACKAGE_NAMES=$(echo $PACKAGES | tr -d '\n')
export BUILD_NUM=$CIRCLE_BUILD_NUM
export SHA1=$CIRCLE_SHA1
echo "Testing the following packages:"
echo $PACKAGE_NAMES
gotestsum --junitfile $ARTIFACTS_DIR/report.xml -- -covermode=count -coverprofile=$ARTIFACTS_DIR/coverage_tmp.out -p 1 $PACKAGE_NAMES
- save_cache:
key: go-mod-1-13-v1-{{ checksum "go.mod" }}-{{ checksum "go.sum" }}
paths:
- "/go/pkg/mod"
让我们回顾一下我们所做的。
首先,我们恢复了 Go 模块缓存。如果没有缓存,则什么都不做。这使我们可以避免每次运行时都必须下载 Go 模块。缓存是由 go.mod 和 go.sum 文件哈希决定的。
run 步骤列出了所有的包,按时间分割它们,并使用 gotestsum 来运行测试。Gotestsum 可以生成 junit 报告,这使得查看哪些测试失败变得很容易。
最后,如果 go.mod 和 go.sum 文件发生了更改,我们将保存缓存。如果该缓存键已经保存,则该步骤不做任何事情。
仅此一项就将我们的工作流程时间从 15 分钟缩短到了 5 分钟。这里的主要好处是,随着测试数量的增加,我们可以简单地增加我们的并行计数。
我们本可以就此打住,但我们认为我们应该尝试看看我们还能做些什么。
原来,我们安装一些所需工具的一个设置步骤花了大约一分钟。我们构建了一个安装了所有工具的新映像,这将构建时间缩短了 30 到 45 秒。这里要注意的是,CircleCI 会更快地提取常用图像,因为它们使用得更频繁,因此会被缓存,所以在您决定制作自定义图像之前,请确保您测量了节省的时间。
集成测试改进:节省时间和降低代码复杂性
集成测试是另一种完全不同的东西。我们运行两种类型的浏览器自动化测试:使用 Chrome 等无头浏览器的本地浏览器测试,以及使用 Browserstack 或 Saucelabs 等服务的远程浏览器测试。虽然本地测试只受我们的 CircleCI 计划限制,但远程浏览器测试可能会变得昂贵,因为您需要为并行性付费。我们使用 CircleCI 来支持我们的远程浏览器自动化测试,Browserstack 托管远程浏览器。
优化重新运行时拆分测试
我们针对三种环境运行集成测试:试运行、沙盒和生产。我们在沙盒上运行的测试最多,在试运行上运行的较少,在生产上只运行一小部分。我们需要能够通过 API 触发我们的集成测试,由于 API 的 v1 不允许这样做,我们构建了一个非常复杂的系统来实现我们所需要的。然而,有了新的 v2 API ,我们已经能够以更合理的方式重新组织我们的工作流,这种方式更容易理解、更快、更容易使用。
以前,我们有一项工作是在三种浏览器变体上运行数百次远程测试。这意味着即使一个测试失败,我们也必须重新运行整个套件,这需要一个多小时。我们将其分解为八个作业,现在我们只能重新运行失败的作业。我们的新工作流程非常简单,如下所示。
添加新测试时的工作流
一种类型的集成测试工作流是针对集成测试报告的每个拉请求运行的。这确保了我们添加或修改的任何测试都是有效的。这些只运行本地无头浏览器测试,并且这个工作流尽可能保持轻量级。
提升构建的工作流
这些集成测试在 master 上针对我们的一个环境运行:staging、sandbox 或 prod。这些需要更加严格,这就是我们在 Browserstack 上使用多个浏览器的地方。此外,由于并行化的级别受到 Browserstack 的限制,Browserstack 会使并行测试失败,而不是对它们进行排队,因此我们通过对使用 browser stack 的工作流进行排队,在 CircleCI 上形成了一个假队列。
这个片段展示了我们如何对远程浏览器堆栈测试进行排队,但不阻止在 circleCI 中运行的无头 Chrome 测试:
version: 2.1
orbs:
swissknife: roopakv/swissknife@0.8.0
# These parameters are used to run various workflows via the API and
# are not used directly for every PR. by setting the below params
# we can for example run only staging integration tests.
parameters:
run_base_tests:
type: boolean
default: true
run_cdstaging_integration_tests:
type: boolean
default: false
run_staging_integration_tests:
type: boolean
default: false
run_sandbox_integration_tests:
type: boolean
default: false
run_production_integration_tests:
type: boolean
default: false
workflows:
# This workflow is run on master changes merged to this repo
build:
when: << pipeline.parameters.run_base_tests >>
jobs:
- test-on-chrome:
name: Staging on local chrome
context: integration-tests-staging-context
- test-on-chrome:
name: Sandbox on local chrome
context: integration-tests-sandbox-context
- test-api:
name: Staging API
context: integration-tests-staging-context
staging-local-chrome:
when: << pipeline.parameters.run_cdstaging_integration_tests >>
jobs:
- test-on-chrome:
name: Staging on local chrome
context: integration-tests-staging-context
# This workflow is triggered via the API to run tests against the
# staging environment on browserstack and local chrome.
staging:
when: << pipeline.parameters.run_staging_integration_tests >>
jobs:
- swissknife/queue_up_workflow:
max-wait-time: "1800"
workflow-name: "^(staging|production|sandbox)$"
- test-on-chrome:
name: Staging on local chrome
context: integration-tests-staging-context
- bs-base:
name: Staging BS base tests
context: integration-tests-staging-context
requires:
- swissknife/queue_up_workflow
- bs-shopify:
name: Staging BS shopify tests
context: integration-tests-staging-context
requires:
- swissknife/queue_up_workflow
- bs-bigcommerce:
name: Staging BS bigcommerce tests
context: integration-tests-staging-context
requires:
- swissknife/queue_up_workflow
- test-api:
name: Staging API
context: integration-tests-staging-context
# This workflow is triggered via the API to run tests against the
# sandbox environment on browserstack and local chrome.
sandbox:
when: << pipeline.parameters.run_sandbox_integration_tests >>
jobs:
- swissknife/queue_up_workflow:
max-wait-time: "1800"
workflow-name: "^(staging|production|sandbox)$"
- test-on-chrome:
name: Sandbox on local chrome
context: integration-tests-sandbox-context
- bs-base:
name: Sandbox BS Base tests
context: integration-tests-sandbox-context
requires:
- swissknife/queue_up_workflow
- bs-shopify:
name: Sandbox BS Shopify tests
context: integration-tests-sandbox-context
requires:
- swissknife/queue_up_workflow
- bs-bigcommerce:
name: Sandbox BS bigcommerce tests
context: integration-tests-sandbox-context
requires:
- swissknife/queue_up_workflow
- bs-woocommerce:
name: Sandbox BS woocommerce tests
context: integration-tests-sandbox-context
requires:
- swissknife/queue_up_workflow
- bs-miva:
name: Sandbox BS miva tests
context: integration-tests-sandbox-context
requires:
- swissknife/queue_up_workflow
- bs-magento1:
name: Sandbox BS magento1 tests
context: integration-tests-sandbox-context
requires:
- swissknife/queue_up_workflow
- bs-magento2:
name: Sandbox BS magento2 tests
context: integration-tests-sandbox-context
requires:
- swissknife/queue_up_workflow
# This workflow is triggered via the API to run tests against the
# production environment on browserstack and local chrome.
production:
when: << pipeline.parameters.run_production_integration_tests >>
jobs:
- swissknife/queue_up_workflow:
max-wait-time: "1800"
workflow-name: "^(staging|production|sandbox)$"
- test-on-chrome:
name: Prod on local chrome
context: integration-tests-production-context
- bs-base:
name: Prod BS Base tests
context: integration-tests-production-context
requires:
- swissknife/queue_up_workflow
请注意,我们在暂存和沙盒环境中有相同的作业。测试是相同的,所改变的只是我们测试的环境,所以我们将测试配置移动到上下文中,并根据被测试的环境附加一个上下文。
我们使用 Jenkins(出于合规性原因)来管理我们的部署和触发集成测试。现在,我们很容易在 Jenkins 上触发集成测试并等待它们。这个是我们如何使用新的 v2 API 实现这一点的示例:
#!/bin/bash -x
# Exit immediately if a command exits with a non-zero status.
set -e
if [ "$1" == "" ]; then
echo "Usage: $0 env"
exit 1
fi
ENV=$1
SLUG=$2
PIPELINE_ID=""
WORKFLOW_ID=""
WORKFLOW_STATUS="running"
start_integration_test () {
CREATE_PIPELINE_OUTPUT=$(curl --silent -X POST \
"https://circleci.com/api/v2/project/${SLUG}/pipeline?circle-token=${CIRCLE_TOKEN}" \
-H 'Accept: */*' \
-H 'Content-Type: application/json' \
-d '{
"branch": "master",
"parameters": {
"run_'${ENV}'_integration_tests": true,
"run_base_tests": false
}
}')
PIPELINE_ID=$(echo $CREATE_PIPELINE_OUTPUT | jq -r .id)
echo "The created pipeline is ${PIPELINE_ID}"
# Sleep till circle starts a workflow from this pipeline
# TODO(roopakv): Change this to a curl loop instead of a sleep
sleep 20
}
get_workflow_from_pipeline () {
GET_PIPELINE_OUTPUT=$(curl --silent -X GET \
"https://circleci.com/api/v2/pipeline/${PIPELINE_ID}?circle-token=${CIRCLE_TOKEN}" \
-H 'Accept: */*' \
-H 'Content-Type: application/json')
WORKFLOW_ID=$(echo $GET_PIPELINE_OUTPUT | jq -r .items[0].id)
echo "The created worlkflow is ${WORKFLOW_ID}"
echo "Link to workflow is"
echo "https://circleci.com/workflow-run/${WORKFLOW_ID}"
}
running_statuses=("running" "failing")
wait_for_workflow () {
while [[ " ${running_statuses[@]} " =~ " ${WORKFLOW_STATUS} " ]]
do
echo "Sleeping, will check status in 30s"
sleep 30
WORFLOW_GET_OUTPUT=$(curl --silent -X GET \
"https://circleci.com/api/v2/workflow/${WORKFLOW_ID}?circle-token=${CIRCLE_TOKEN}" \
-H 'Accept: */*' \
-H 'Content-Type: application/json')
WORKFLOW_STATUS=$(echo $WORFLOW_GET_OUTPUT | jq -r .status)
echo "The workflow currently has status - ${WORKFLOW_STATUS}."
done
if [ "$WORKFLOW_STATUS" == "success" ]; then
echo "Workflow was successful!"
exit 0
else
echo "Workflow did not succeed. Status was ${WORKFLOW_STATUS}"
exit 1
fi
}
# remove noise so set +x
set +x
start_integration_test
get_workflow_from_pipeline
wait_for_workflow
从单一工作转移到这种工作流控制的方法给我们带来了以下好处:
- 能够只重新运行部分测试,而不是全部测试
- 缩短时间
- 我们现在在 CircleCI 上下文中使用 config,而不是使用复杂的代码来处理多种环境。
结论
总之,当我们着手减少测试运行时间并使测试更容易工作时,我们意识到我们必须对不同类型的测试使用不同的方法。我们按照运行时间分割单元测试,并且将任何可能的重复工作转移到一个预构建的容器中。至于集成测试,我们优化了有限并行的远程浏览器。我们构建了一种机制,通过简单的配置更改跨环境运行相同的测试。因此,我们还降低了管道的复杂性,这使得新工程师更容易理解我们的测试基础设施。
Roopak Venkatakrishnan 目前正在为 Bolt、Google 和 Twitter 构建系统。除了解决复杂的问题,他对开发基础设施&工具有着强烈的爱好。当他不工作的时候,他喜欢喝一杯咖啡,徒步旅行,发一些随意的微博。
阅读 Roopak Venkatakrishnan 的更多帖子
我如何使用基础设施作为代码?- Terraform 和 Pulumi | CircleCI
基础设施即代码(IaC)是通过机器可读的定义文件管理和供应云和 IT 资源的流程,是现代持续集成管道的一部分。IaC 使组织能够使用现代 DevOps 工具调配、管理和销毁计算资源。IaC 通过在代码中静态定义和声明这些资源,然后通过代码部署和动态维护这些资源来实现这一点。
在最近与开发人员的交流中,我意识到许多人要么不知道 IaC,要么知道但因为升级太麻烦而放弃了最初的努力。在这篇文章中,我将讨论 IaC 的好处和一些目前可用的工具选项,并简要演示如何使用它们,希望能够简化向使用 IaC 的过渡。我将重点介绍当今业界使用的两个最流行的 IaC 工具: HashiCorp 的 Terraform 和的 Pulumi 。
先决条件
在你开始之前,你需要有这些东西:
创建 Google 云项目证书
您将需要创建 Google Cloud 凭证,以便使用 IaC 工具执行管理操作。
- 转到创建服务帐户密钥页面
- 选择默认服务帐户或创建一个新帐户,选择 JSON 作为密钥类型,然后单击创建
- 将这个 JSON 文件保存在
~/.config/gcloud/
目录中,并将文件重命名为cicd_demo_gcp_creds.json
。这对稍后在容器中启用谷歌云 CLI 非常重要
创建 Pulumi API 令牌
您将需要获得一个 Pulumi API 令牌来将您的项目状态存储在 Pulumi 的后端云中。
- 前往app.pulumi.com/
- 点击页面左上方的选择一个组织并选择您的账户
- 点击设置
- 点击页面左侧的访问令牌
- 点击页面右侧的新建访问令牌
- 点击创建并保存创建的新 API 令牌。这将用于稍后初始化您的 Pulumi 项目
Docker pull IaC101 Docker 图像
至此,所有先决条件都已完成,您已经准备好为本次研讨会提取 docker 映像了。在终端中键入以下命令:
docker pull ariv3ra/iac101
现在您应该在本地拥有了ariv3ra/iac101
docker 映像。您可以验证 buy running docker images
,您应该会看到结果中列出的图像。
码头运行 IaC101 集装箱
现在我们将基于ariv3ra/iac101
图像创建一个新的 Docker 容器,其中包含所有的 IaC 工具和代码。
安装/。配置/gcloud/目录
在运行新容器之前,您需要到您的~/.config/gcloud/
目录的绝对路径。在我的 MacOS 机器上,我的绝对路径是/Users/angel/.config/gcloud/
。确保获得本地机器上gcloud
目录的绝对文件路径。
运行带有装载的 IaC101 容器
在终端运行中运行这个命令,但是一定要用本地glocud/
目录的实际绝对路径替换<your absolute path here>
位:
docker run -it --name iactest --mount type=bind,source=<your absolute path here>.config/gcloud/,target=/root/.config/gcloud/ ariv3ra/iac101
IaC101 容器正在运行
运行前面的docker run
命令后,您的 IaC101 容器将启动并运行,您的终端 shell 将您放入运行容器中。从现在开始,您在终端 shell 中运行的每个命令都将在 Docker 容器中执行,直到您手动exit
该容器。该容器安装了 Terraform 和 Pulumi CLI 工具,以及在各自工具中创建基础设施的示例代码。容器项目文件映射如下。
projects/
|_ terraform/gcp/compute/ # Contains the Terraform code files
|_ pulumi/gcp/compute/ # Contains the Pulumi code files
哈希公司地形
HashiCorp Terraform 是一款开源工具,用于安全高效地构建、更改和管理基础设施。Terraform 可以管理现有的服务提供商以及定制的内部解决方案。
配置文件描述了在 Terraform 上运行单个应用程序或整个数据中心所需的组件。Terraform 生成一个执行计划,描述它将如何达到期望的状态,然后执行它来构建所描述的基础设施。随着配置的改变,Terraform 能够确定改变了什么,并创建可应用的增量执行计划。
Terraform 可以管理的基础设施包括低级组件,如计算实例、存储和网络,以及高级组件,如 DNS 条目、SaaS 功能等。
使用 Terraform 调配基础架构
让我们从使用 Terraform 代码在 GCP 提供一些资源开始。terraform/gcp/compute/
中的main.tf
是定义我们的基础设施的代码。在该文件中,我们将创建一个新的计算实例,该实例将安装并运行打包在 Docker 容器中的 Python Flask 应用程序。Terraform 代码还将创建一些防火墙规则,允许公众通过端口 5000 访问应用程序。
要对此进行配置,请在终端中运行以下命令:
cd ~/project/terraform/gcp/compute/
初始化地形
在~/project/terraform/gcp/compute/
中运行该命令:
terrform init
您将看到类似于下面的结果。
root@d9ce721293e2:~/project/terraform/gcp/compute# terraform init
Initializing the backend...
Initializing provider plugins...
- Checking for available provider plugins...
- Downloading plugin for provider "google" (hashicorp/google) 3.10.0...
* provider.google: version = "~> 3.10"
Terraform has been successfully initialized!
使用地形预览
Terraform 有一个命令,允许您在不实际执行任何操作的情况下,模拟运行和验证您的 Terraform 代码。该命令名为terraform plan
,它还绘制了 Terraform 将针对您现有的基础设施执行的所有操作和更改。在终端运行中:
terraform plan
您将看到类似这样的结果。
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# google_compute_firewall.http-5000 will be created
+ resource "google_compute_firewall" "http-5000" {
+ creation_timestamp = (known after apply)
+ destination_ranges = (known after apply)
}
# google_compute_instance.default will be created
+ resource "google_compute_instance" "default" {
+ can_ip_forward = false
+ cpu_platform = (known after apply)
+ deletion_protection = false
+ guest_accelerator = (known after apply)
+ id = (known after apply)
+ instance_id = (known after apply)
+ label_fingerprint = (known after apply)
+ labels = {
+ "container-vm" = "cos-stable-69-10895-62-0"
}
+ machine_type = "g1-small"
}
Plan: 2 to add, 0 to change, 0 to destroy.
如您所见,Terraform 将根据main.tf
文件中的代码为您创建新的 GCP 资源。
地形应用
现在,您已经准备好创建新的基础设施并部署应用程序了。在终端中运行以下命令:
terraform apply
Terraform 将提示您确认您的命令。键入 yes 并按回车键。
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
Terraform 将构建您的基础设施,完成后不久,您将在 GCP 上安装并运行一个应用程序。请注意,Terraform 完成后,应用程序将需要 3-5 分钟才能上线。这不是一个即时的过程,因为后端系统正在进行供应和上线。
一旦完成,您将看到类似这样的结果。
Outputs:
Public_IP_Address = 34.74.75.17
Public_IP_Address
值是你的应用程序运行的 IP 地址,所以如果你打开浏览器,输入这个数字加上:5000
端口地址(看起来像这个34.74.75.17:5000
),你会看到你的应用程序在 GCP 运行。
地形破坏
既然您已经证明了您的 Google Compute 实例和您的应用程序可以工作,那么运行terraform destroy
命令来销毁您在本教程中创建的资产。你可以让它继续运行,但要知道,在谷歌云平台上运行任何资产都是有成本的,你要为这些成本负责。谷歌为其免费试用注册提供了慷慨的 300 美元信用,但如果你让资产运行,你可以很容易地吃掉它。由你决定,但是运行terraform destroy
会终止任何运行的资产。
接下来,我将演示如何使用 Pulumi 执行基础设施供应。
Pulumi SDK
Pulumi SDK 是一个开源框架,用于定义和部署云应用和 IaC。Pulumi 使开发人员能够用他们喜欢的语言编写代码,如 TypeScript、JavaScript、Python 和 Go。这实现了云应用和基础设施的现代方法,而无需学习另一种 YAML 或 DSL 方言。这开启了抽象和重用,以及对您喜欢的 ide、重构和测试工具的访问。掌握一个工具链和一套框架,轻松地转向任何云(AWS、Azure、GCP 或 Kubernetes)。
使用 Pulumi 配置基础架构
您已经体验了使用 Terraform 构建基础设施,现在您将学习如何使用 Pulumi 配置和部署新的基础设施。Pulumi 示例将使用 Pulumi 代码和工具创建相同的 GCP 资源。Pulumi 使您能够用编程语言定义基础设施,这提供了很大的灵活性。在这个例子中,我们使用 Python 作为我们的语言。~/project/pulumi/gcp/compute/
目录中的__main.py__
文件是我们将要定义基础设施的地方。
确保您的 Pulumi API 令牌可用。在接下来的章节中,您会用到它。
Pulumi 示例可以在~/project/pulumi/gcp/compute/
目录中找到。运行以下命令切换到 Pulumi 示例目录:
cd ~/project/pulumi/gcp/compute/
为 pulumi 安装依赖项
因为我们使用 Python 定义 IaC 规范,所以我们需要首先安装 Pulumi Python SDK 依赖项。在终端中运行以下命令:
pip install -r ../requirements.txt
使用 Pulumi 预览
Pulumi 有一个名为pulumi preview
的预演命令。此命令显示现有堆栈更新的预览,现有堆栈的状态由现有状态文件表示。新的期望状态是通过运行 Pulumi 程序并从其结果对象图中提取所有资源分配来计算的。然后,将这些分配与现有状态进行比较,以确定必须进行哪些操作才能达到期望的状态。实际上不会对堆栈进行任何更改。
在终端中运行以下命令:
pulumi preview
运行该程序后,您将看到以下结果,提示您输入之前创建的 Pulumi API 令牌。将令牌粘贴到终端中。粘贴令牌后,点击 enter。
Manage your Pulumi stacks by logging in.
Run `pulumi login --help` for alternative login options.
Enter your access token from https://app.pulumi.com/account/tokens
or hit <ENTER> to log in using your browser :
注意: 将 API token 粘贴到终端时,不会显示任何值。出于安全目的,它将保持不可见。
可能会提示您在终端中选择一个堆栈。如果是,选择dev
选项,然后点击回车。您将看到类似这样的结果。
Previewing update (dev):
Type Name Plan
+ pulumi:pulumi:Stack compute-dev create
+ ├─ gcp:compute:Network network create
+ ├─ gcp:compute:Address workshops-infra-as-code101 create
+ ├─ gcp:compute:Instance workshops-infra-as-code101 create
+ └─ gcp:compute:Firewall firewall create
Resources:
+ 5 to create
您刚刚启用了对 Pulumi 后端云的访问,它会跟踪您的基础设施的状态。现在您已经准备好运行一些代码了。
Pulumi up
要执行 Pulumi 代码,请使用命令pulumi up
。该命令创建或更新堆栈中的资源。通过运行当前的 Pulumi 程序并观察所有的资源分配来产生一个资源图,可以计算出目标栈的新的期望目标状态。然后,将该目标状态与现有状态进行比较,以确定必须进行哪些创建、读取、更新和/或删除操作,从而以破坏性最小的方式实现期望的目标状态。之后,该命令记录堆栈新状态的完整事务快照,以便以后可以再次增量更新堆栈。
在终端运行中:
pulumi up
选择yes
选项并按下回车键。Pulumi 应用程序将会执行,很快您将拥有一个完整的服务器,在 GCP 上运行应用程序。您将看到类似这样的结果。
Updating (dev):
Type Name Status
+ pulumi:pulumi:Stack compute-dev created
+ ├─ gcp:compute:Network network created
+ ├─ gcp:compute:Address workshops-infra-as-code101 created
+ ├─ gcp:compute:Firewall firewall created
+ └─ gcp:compute:Instance workshops-infra-as-code101 created
Outputs:
external_ip : "34.74.75.17"
instance_meta_data: {
gce-container-declaration: "spec:\n containers:\n - name: workshops-infra-as-code101\n image: ariv3ra/workshops-infra-as-code101:latest\n stdin: false\n tty: false\n restartPolicy: Always\n"
}
instance_name : "workshops-infra-as-code101"
instance_network : [
[0]: {
accessConfigs : [
[0]: {
natIp : "34.74.75.17"
network_tier : "PREMIUM"
}
]
name : "nic0"
}
]
Resources:
+ 5 created
Duration: 58s
在这些结果中,您会看到一个external_ip
键。它的值是在端口 5000 上公开的面向公众的应用程序的 IP 地址。就像前面的 Terraform 示例一样,您可以在浏览器中访问应用程序。请记住留出几分钟时间,以便后端系统可以将所有内容上线。
普鲁米毁灭
Pulumi 有一个命令可以终止所有名为pulumi destroy
的云资源。此命令按名称删除整个现有堆栈。当前状态是从工作区的相关状态文件中加载的。运行完成后,该堆栈的所有资源和相关状态都将消失。
在终端运行pulumi destroy
,当提示永久销毁创建的 GCP 资源时,选择yes
选项。
摘要
恭喜你!您刚刚升级,现在已经有了使用现代 IaC 工具 Terraform 和 Pulumi 向 GCP 供应和部署应用程序的经验。以下资源将帮助您扩展知识:
美元剃须刀俱乐部持续集成(CI)| CircleCI
原文:https://circleci.com/blog/how-dollar-shave-club-3x-d-velocity-and-learned-love-tests/
当 Dollar Shave Club 开始使用 CircleCI 时,他们发现它不仅改善了他们的 CI/CD 渠道,还改善了他们的生产监控和发布管理操作,同时使他们的开发人员的生活更加轻松。他们来找我们,希望分享他们向 CI 过渡的故事,以及使用 CircleCI 如何帮助他们改善开发人员体验,同时提高他们的软件质量和交付速度。请继续阅读他们的故事。
过渡到 CI/CD
由 Dollar Shave Club 工程经理 Jon Ong 和后端工程师 Yuki Falcon
2017 年,我们从手动测试每个代码变更切换到测试自动化的 CI/CD。这一变化为我们打开了一些新的可能性,极大地改善了我们的工作流程。以下是我们因这一转变而开辟的一些最大的途径:
我们可以使用功能标志和/或 A/B 测试来暗启动新功能。分离部署和特性发布带来了一些巨大的好处。我们能够在生产中进行用户验收测试。由于在开发过程的早期获得了利益相关者的输入,反馈循环得到了加速和改进。此外,我们能够更快、更频繁地投入生产,这有其自身的好处,如更高的工程速度、更好的代码审查和更容易的回归原因跟踪。
每个部署不再需要 QA 签准。工程师现在主要负责他们之间的代码质量。这增加了我们 QA 部门的整体带宽,允许他们将注意力从手工回归测试转移到整体测试。他们还能够在我们产品设计周期的早期提供用户/功能反馈。
我们的前端团队现在可以直接投入生产。绕过我们的共享试运行环境迫使我们增加对 CI 测试和我们的动态试运行环境(DQAs) 的依赖。dqa 是由我们自己的基础设施&平台服务工程经理 Benjamin Keroack 创建的,是生产环境的复制品,整合了拉式请求变更。
我们使用珀西进行可视化回归测试,使用 Codecov 进行代码覆盖分析,使用滚动条进行错误监控。
改进我们的 CI 测试
对 CI 测试越来越多的依赖迫使我们修改我们的测试策略。到目前为止,我们的测试前景是暗淡的。我们的单元测试在 CircleCI 1.0 上运行,端到端(e2e)测试在 Jenkins 上运行。然而,CircleCI 1.0 上的单元测试并不理想,因为它的并行性策略和我们测试的片面性。詹金斯逐渐无法应付这种规模。事实上,我们使用的许多测试套件并不好,主要是由于我们编写测试的方式。Ruby Selenium 中糟糕的测试模式导致了不一致的结果。Ember 验收测试是粗制滥造的,因为腐烂的代码,没有按照测试套件的意图编写的测试,以及不可靠的测试框架。
为了解决这些令人头疼的问题,我们实施了一些解决方案。首先,我们重写了我们的 e2e 测试运行器,以支持并行性和测试的自动重试。在 Sauce Labs 上进行的重试为我们提供了网络请求的记录。其次,我们迁移到 CircleCI 2.0 工作流,这允许我们将测试分成几个不同的任务,从而简化重试并增加并行性。
结果比我们希望的要好。CircleCI 2.0 的工作速度是 CircleCI 1.0 的两倍。我们的 e2e 测试从 30-40 分钟缩短到大约 15 分钟。工程师们注意到了 UX 的改进,对测试失败的抱怨也少了。前端工程师编写了他们自己的自动化测试,提高了测试的可靠性、速度和可调试性。
CircleCI 2.0 允许我们只重新运行失败的测试,而不是重新运行整个测试套件。
提高开发者 UX
我们通过自动触发 CI/CD 进一步改进了开发者 UX。
自动更新依赖关系
我们使用 Greenkeeper 在依赖关系发布新版本时自动生成 PRs,并在更新时更新我们的锁定文件。通过自动合并,当所有要求的检查(林挺、测试、监控)通过时,请购单会自动合并。工程师现在可以通过批准这些 Greenkeeper PRs 并将其标记为“自动合并”来固定依赖关系并使其保持最新。我们还可以很容易地找出哪些依赖关系破坏了我们的应用程序。
监控我们的拉动式请求 CI/CD 渠道
每 15 分钟创建一次无代码变更 PRs,以跟踪我们的 CI/CD 管道的运行情况。这些信息会发送到 DataDog,在我们的 CI/CD 渠道出现问题时提醒我们。
结论
切换到 CircleCI 2.0 并让工程师编写他们自己的测试是一个有利的决定。我们现在有了更快、更可靠的 CI/CD 渠道。我们的工程师只担心 Git 工作流(创建 PRs,获得批准,通过 GitHub 检查,按下 merge)和特性实现。工程师们现在需要掌握几十个小提交,而不是每天几个,从而提高了速度和查明回归的能力。编码快乐!
工程经理如何有效地支持工程师、团队和组织
许多工程经理角色的典型工作描述是充满行动的。它是动手编程、技术领导和决策制定、过程和项目管理、产品监督、人员管理、发现和雇佣人才的混合体……不胜枚举。
在我们的工作中,我们处理技术和人员系统:我们支持个人工程师的成长;帮助团队走向成功;并使组织更具生产力、功能性和创新性。最重要的是,工程经理是跨越这些不同层次的服务或支持角色。
也许最令人着迷和困难的是工程管理带来的高度模糊性。许多问题没有直接的答案。对于成为一名优秀的工程经理意味着什么,也没有绝对的答案,但是有一些特定的价值观和指南可以遵循。
在这篇文章中,我将探讨是什么塑造了我们作为工程经理的角色,以及如何有效地支持单个工程师、团队和组织。
工程师需要什么才能在工作中茁壮成长?
通过了解工程师需要什么,以及他们成长的环境,这有助于开始塑造工程管理角色。来自绩效教练和培训师 Paloma Medina 的研究揭示了人类的六种核心需求(包括在工作中)。她称这项研究为二头肌模型:
- 归属。作为人类,我们努力成为志趣相投的群体中的一员,在这里我们相互理解、相互支持。我们也想感觉我们没有被歧视或边缘化。归属感对我个人来说真的很重要:我喜欢作为分布式团队的一员工作,但我也很喜欢偶尔亲自见见别人。这让我觉得和他们更有联系。
- 改善。我们还寻求在对我们以及我们的团队或公司重要的领域不断学习、提高和成长。
- 选择。我们希望对生活中的重要部分拥有选择权、控制权和自主权。在我之前的一份工作中,我承担了大量推动组织变革的工作。但最终,由于组织问题,我对自己领域的控制受到了限制,这导致我离开了公司。
- 平等。我们希望知道,我们对信息、金钱、时间和其他资源的获取对每个人都是公平和平等的——不仅对我们自己,对我们周围的人也是如此。每个人的需求都应该同等重要。
- 可预见性。我们在生活中寻找确定性、安全性和稳定性。我们还希望目标、战略和方向保持一致——并且不要改变得太快。过去几年,我一直在快速增长的初创公司中领导团队,当有很多变化发生时,给团队灌输可预测性是一个挑战。
- 意义。在内心深处,我们都在寻找意义、重要性和地位。我们也希望我们的工作能得到那些对我们有意义的人的赞赏。
如果我们的核心需求受到威胁,人们会采取“战斗或逃跑”的反应模式,这是非常令人紧张的。未能满足核心需求会伤害我们团队的成员,从而使组织付出高昂的代价。那么,工程经理如何将二头肌模型付诸行动,以帮助他们的团队蓬勃发展呢?
利用基于信任的关系帮助工程师成长
成为一名优秀工程经理的基础是了解我们的队友,并理解什么对他们来说是重要的。这里有几个开始在你的团队中建立信任的地方。
提问。管理者拥有的最强有力的工具之一就是提出好问题。做好我们工作的基础是倾听、观察、记录激励我们队友的因素,并真正挖掘他们对我们问题的回应。我通常在与队友一对一会面之前收集问题,所以我有所准备,我可以引导谈话更好地理解他们。随着时间的推移,我已经建立了一套一对一的问题,当我需要一些灵感来进行这些对话时,我就会拿出来。提问有助于我们根据所领导的人来调整自己的领导风格。这也确保他们感到被理解和倾听,这是包容和归属感的真正重要支柱。
好奇。人都是充满惊喜的,有时候队友的反应可能和我们预想的完全不一样。我曾经收到我团队中一位工程师的消息,他对给客户的产品发布通知中使用的特定措辞深感不安。起初我不理解他们的强烈反应。但当我们交谈时,我了解到工程师被更有权力的人否决了,这让他们感到无助,并威胁到他们对选择和平等的核心需求。
经理们可能认为没什么大不了的事情对其他人来说可能是巨大的威胁。我们对队友的反应感到惊讶的情况是关注以人为中心的反应的好机会,比如给人们机会说出他们的感受。
连接到更大的图片。创造影响力对我们所有人来说都是一个非常好的激励因素,因此帮助工程师理解他们的工作如何与更大的图景联系起来(它如何帮助用户或支持其他团队)对经理来说是一项极其重要的战略技能。虽然像 OKRs 这样的目标设定框架可以有所帮助,但将工程计划与更高层次的目标结合起来,并将它们与用户价值明确联系起来也是至关重要的。
让工程师参与决策。感觉决策公平公正是二头肌模型的重要组成部分。当我们做决定时,先征求每个人的意见,并把他们的意见考虑进去,这是有帮助的。并不总是可能符合每个人的要求。但是我们仍然可以做得很好,将我们所做的决定联系起来,帮助人们理解他们的反馈是被考虑的。
为成长提供反馈。作为工程经理,我们能做的最好的事情之一就是支持工程师的成长。定期提供反馈,以帮助团队成员了解他们的现状和成长——通过在需要的地方进行课程修正,以及在他们已经做得很好的领域做得更多。经理也需要反馈:定期向你的团队征求反馈很重要,这样你就可以做出调整。
蔻驰工程师。辅导帮助人们自己寻找答案,提高他们解决问题和领导能力,并增加学习、适应力和自我管理。
赞助商工程师。回想一下你的职业生涯,你是否有过一个导师将你与某人联系起来,让你扬名立万,并利用他们的影响力来改变你的职业生涯。为他人做那个人:投资于他们的成长,鼓励他们,支持他们的成功。支持你的团队取得成功可以为他们带来真正的改变。
这是我们作为工程经理的工作基础。
在团队中推动信任和持续改进的文化
作为工程经理,我们工作的下一个重要组成部分是团队。根据研究,高绩效团队需要以下要素。
- 心理安全。这是关于相信我们不会被拒绝,并自由地向周围的人表达我们与工作相关的想法和感受。这也意味着相信,如果我们犯了一个善意的错误或寻求帮助,别人不会看轻我们。
- 结构和清晰度。团队中的每个人都应该理解期望、目标和责任。
- 意义和影响。高绩效团队在工作中找到目标感,并知道他们的工作会产生影响。
幸运的是,对于管理者来说,这项研究恰好符合二头肌模型。所有人的核心需求都得到了体现,并对团队层面产生了影响。通过理解和回应人们的动机,领导者为团队表达自己创造了基础——并提供了他们需要的结构、意义和影响。
建立信任。建立结构的第一步是建立关系。对于我们在 CircleCI 的分布式团队,我们已经建立了不同的结构来帮助队友做到这一点,例如定期的结对编程轮换和工程会谈。
围绕我们如何合作的结构。我们位于 CircleCI 的工程部门已经连续三年扩大了一倍。在这段时间里,我们为所有团队转移到了一个更加简化的工程交付过程。但是我们仍然让团队来决定如何实现日常流程,包括每日站立会议、计划会议或协作。每个团队都有特定的需求,他们最知道如何满足这些需求。
移除拦截器。结构也有助于减轻工作受阻的影响。我们都知道被卡住是多么令人沮丧。建立帮助人们畅通无阻的途径可能非常重要——例如,建立定期结对编程循环,投资自助信息访问,跨团队相互支持,建立人们在需要时获得帮助的升级途径,或通过知识共享帮助人们相互支持。
持续改进。我们可以利用回顾来讨论和改进我们的合作方式。无可指责的事后分析也是帮助理解问题和寻求解决方案的一个很好的工具。代码审查、指导或知识共享可以帮助团队成员相互学习。我们谈论学习的方式很重要——尤其是我们讨论错误的方式。这些决定将从根本上塑造我们团队的文化,并决定人们在他们的核心需求中是感到安全还是受到威胁。
向直线行驶。向我们的团队传达战略、方向和相关的战术细节——记住,几乎不可能过度传达这些细节。总是重复重要的事情。
作为工程经理,我们就像砂浆:我们连接结构、团队和人。我们将它们结合在一起,但也根据需要识别和填补空白。处理模糊性是工程管理中最重要也是最困难的方面之一..对于我们这个领域的很多工作来说,没有直接的答案,更不用说解决方案了。
我们的工作不仅仅是关于我们自己;这是关于我们支持的人、团队和组织。我们建造帮助他人发光的结构。
支持组织变革
最后,创造工程师可以茁壮成长的环境是为了支持我们的组织。无论我们的企业规模有多大,我们都需要利用我们作为管理者的权力来推动组织变革。
主张变革。要成为高效的管理者,我们需要推动组织变革,以改善我们周围的大型结构。例如,我们可能需要倡导工程经理角色更加清晰,就我们公司的工程管理应该是什么样的进行对话,并确定雇用工程经理的要求。
管理起来。管理我们自己的经理是一项有用但困难的技能。推动组织变革还意味着确保我们的工程师所关心的问题能够被最高层听到,并且我们利用我们的力量来确保工程师在组织的其他部门也有发言权。
建立框架和标准。尽管为个人需求留出空间总是很重要,但管理者的结构和框架有助于我们相互问责。他们也有助于创造公平的竞争环境,为我们团队中的人营造平等的氛围。在我目前的团队中,每个季度我们都会挑选一些高优先级的项目来改善我们作为一个组织的工作方式。最近,我们致力于招聘流程和事故补救;去年,我们为工程师开发了一个内部职业发展框架。
成长为领导者
成为一名优秀的工程经理并不总是一帆风顺的;这在很大程度上取决于我们在职业生涯中所处的位置和我们的发展方向,以及我们组织的成长阶段、规模和需求。在我们的日常工作中,我们在努力取得进步的同时,也面临着大量的不确定性。
在我的工程管理工作中,最重要的主题是成长和提高。我们很少处理绿地项目,或者能够从零开始建立一个团队或部门。即使我们这样做,我们也是建立在我们组织的现有结构上。我相信我们的支持角色很大程度上意味着帮助工程师成长,支持团队不断学习,并帮助组织变得更好。
作为工程经理,我们经常会面对一些没有明确正确或错误答案的问题。很多年前,我的领导力教练鼓励我利用那些不确定的情况问自己,“我想成为什么样的领导者?”
我想把成长和改进的最后一个号召留给你(和我):不管你的角色或公司是什么样的,努力塑造你的工程管理方法。了解和你一起工作的人,并利用反馈来帮助他们纠正方向。建立心理上安全的团队,让人们在共同的目标中找到意义。并利用你的权力和特权来推动组织变革。让人们成为你工作的中心和焦点,并在此基础上创造一个他们可以茁壮成长的环境。始终推动持续改进。以谦逊、同理心和大量的好奇心开始。
你想成为什么样的领导者?
如果你对 CircleCI 的工程管理感兴趣,并想和我们一起工作:加入我们吧!我们正在招聘工程经理。
我如何通过学习依靠我的团队从疲惫中恢复过来
原文:https://circleci.com/blog/how-i-came-back-from-burnout-by-learning-to-lean-on-my-team/
一周的天数永远不够。明天总是会带来更多的任务,更多的选择,以及更多做出错误决定的地方。无论你是一个试图寻找市场契合点的创始人,还是一个半夜被传呼的个人贡献者,工作不断到来。
在我职业生涯的早期,我试图接受这个事实。我是一名绿色机构的开发人员,患有严重的冒名顶替综合症。我认为持续的工作漏斗、错过的截止日期、愤怒的客户是我唯一的责任。看起来盈利的责任完全落在了我的肩上,所以我埋头苦干。
因为那是我认为我必须做的。在那一刻,所有这些我无法控制的外部力量都向我袭来,我所能做的就是更加努力地工作,即使这是徒劳的。一年后,12 个多小时的工作时间开始让我头疼。每天早上醒来时,我会比前一天晚上更疲惫;每天晚上,我对第二天的恐惧超过了对前一天的恐惧。
我已经看不到为什么我想进入这个行业,只能看到摆在我面前的难以逾越的障碍和任务。听起来熟悉吗?
职业倦怠是我们这个行业的一种流行病,我们以利润为先的时代精神似乎将它誉为“赢得你的条纹”。从 Paypal 黑手党对“睡在你的桌子下面”运动的赞美,到编程界的陶对一名工程师的描述,他是一个在永无止境的功能列表中辛勤工作直到筋疲力尽的人,疲惫仅仅是一个需要克服的障碍的想法在我们的社区中回荡,这是有害的。
不一定要这样。当我们开始我们的软件之旅时,痛苦并不是我们想要的。“为了团队”而受苦无助于我们团队的成功。
在我的团队的小手会上,我想起了这一点——我们职能团队的一次面对面的全体聚会。作为一个完全分散的团队,这是我们第一次有机会在同一个时区共度美好时光,更不用说在同一栋大楼里了。随着沟通能力的同步发展,我们在回顾过程中的情感也变得更加开放。与团队的交谈让我注意到了我正在经历的精疲力竭的迹象:失眠、冷漠,以及跑完就感到腿疼。
像许多其他人一样,我起初逃避这种感觉,选择将我的情绪状态归咎于其他来源,或者将我的头埋在我的电脑里,希望这一次我能克服它。我的团队知道还有更深层的东西,我们一起努力找出那是什么。
当我们开诚布公地谈论我所面临的问题时,我意识到在团队中失败是多么的安全,他们都充满了优雅和同情。团队没有试图掩盖尴尬的对话和情绪,而是提供了安慰,在我所在的地方迎接我,把我扶起来。他们冲向我的任务,并带着它们穿过终点线。
他们关心和同情地对待我和我的情感,并作为一个有凝聚力的单位运作,不仅仅是责任,而是爱和尊重。尽管围绕着破解编码面试式的技能似乎是我们行业的门槛守护者,但这些移情、过度沟通、和感恩的技能是那些可以到达倦怠的深渊并为那些需要它的人提供梯子的技能。
不在于你有多擅长将英文产品需求翻译成 Clojure 或 React 代码,而在于你对团队中最需要帮助的人有多开放和亲切,这些人应该是看门人。
同情心,就像任何其他技能一样,是一种后天习得的特质。我们必须投入同样多的努力,如果不是更多的努力,让它从我们的行动中散发出来,就像我们写“好代码”一样。我们必须在为客户创造真正的价值和确保我们自己感受到价值之间取得平衡。这真的很难。
没有解决精疲力竭的算法,也没有能帮助我们对工作中承受的外部压力感觉更好的启发式方法。作为工程师,这是一个难以接受的事实。我见过很多博客帖子和课程承诺用一个新颖的过程或步骤来防止倦怠。但以我的经验来看,这些只是推迟了不可避免的崩盘,因为它们没有从根本上解决问题。只是没那么简单。
唯一对我或我周围的人有所帮助的是同情和理解;关心桌子后面的人,而不是我们可能产生的 1 和 0。创造富有同情心的工作环境是每个人的责任,这可能是一个艰难的过程。但摆脱倦怠也是如此。我明白了,我宁愿和我的团队一起爬那座山,而不是独自一人。
Lightspeed 优化的 iOS 测试如何与并行和缓存一起运行| CircleCI
原文:https://circleci.com/blog/how-lightspeed-optimized-ios-testing/
在 Lightspeed,我们维护多个大型 iOS 项目及其模块化的依赖关系。去年的收购汇集了我们公司许多不同的 CI/CD 方法。我最近领导了将这些项目和实践结合起来的计划。
在这篇文章中,我将解释我们持续集成管道的目标以及我们用来实现这些目标的实现。
我们需要 CI 提供什么
速度
该团队从一开始就明确表示,总运行时间对他们来说是一笔巨大的交易。快速反馈使他们能够专注于同一项任务。
可靠性
现有的解决方案主要是运行 Jenkins 的内部机器。这有快速构建的好处,但是对它们的维护是开发人员的负担。他们经常需要重新启动,而在疫情的全球分布的团队中,这对生产效率来说并不好。也很难保持干净的环境和统一的设置。
灵活性
在我们研究其他解决方案时,使用的灵活性成了一个问题。我们的每个项目都有许多依赖项,例如跨平台 Appium 测试或需要自制的工具。
标准化
这符合灵活性,但是在每个项目中有一个 CI 标准是有益的,因为知识可以在团队和开发人员之间共享。CircleCI 已经被其他团队和项目独立采用,这帮助我们更有信心选择它作为我们需要的解决方案。
使用 CircleCI 可以满足大部分要求。Circle 的正常运行时间超过 99%,由于其他团队已经在使用它,标准化速度更快。我们的管道中唯一需要工作的方面是执行速度。当我们第一次完成 CircleCI 配置文件的最基本迭代时,我们的运行时间超过了一个小时(1.5 小时)。相对于我们的自托管机器,这是一个巨大的增长,自托管机器的运行时间不到一半(30 分钟)。
我们为提高运行时间所做的三大改变
平行
并行性是改善任何 CI 工作流程的重要组成部分。将测试分割成并发流意味着运行时间减少到运行时间最长的任务的长度。此外,使用 CircleCI 作业进行拆分使我们能够重新运行单个作业,大大减少了重新运行时间。
测试 iOS 应用程序比测试 web 应用程序更复杂,因为我们需要传递构建好的二进制文件,以便测试有所依据。为此,我们在config.yml
中创建了两个工作。
建造
- 检查代码
- 恢复缓存
- 捆绑安装
- 安装 Cocoapods
- 从 Brewfile 安装
- 安装基于 SPM 的工具
- 解决 Swift 包裹依赖性
- 构建派生数据
- 保存新缓存
- 保留到工作区
运行
- 附加到工作区
- 捆绑安装
- 跑浪子巷
- 准备存储测试结果
- 存储测试结果
- 存储工件
CircleCI 中 iOS 并行的关键是persist_to_workspace
,它将保存您定义的路径,以便其他作业可以访问它们。由于每个作业都是一个干净的实例,这就是我们在它们之间维护状态的方式。
持久化整个项目,包括来自构建的派生数据,对于我们的主项目来说将近 8Gb。这本身就需要 10 分钟来上传和再次下载。通过只保存所需的文件和文件夹,我们看到了更好的性能:
- persist_to_workspace:
root: /Users/distiller # Default path for a Circle job
paths:
- project/DerivedData/Build/Products # This is the built app that can then be ran against for testing
- project/fastlane # So we can run Fastlane on the parallel jobs
- project/Gemfile # So we can run Fastlane on the parallel jobs
- project/Gemfile.lock # So we can run Fastlane on the parallel jobs
- project/SnapshotTests # Contains the source snapshot images
- 'project/UnitTests/ViewControllerTests/__Snapshots__' # Contains the source snapshot images
- project/commit_author # Used for the Slack message integration in Fastlane
- .gem # So we can run Fastlane on the parallel jobs
我们维护一个共享的浪子车道库,在每个项目中使用。在 CI 服务和我们的底层业务逻辑之间有一个中介者,使得未来的改变更加容易。xcodebuild 和浪子都有能力构建测试,并在不构建的情况下再次运行它们。
运行作业可以简单地检索所有这些存储的状态,方法是:
- attach_workspace: # Gives this job access to the results stored by the build job, so that many parallel jobs can be used from the result
at: /Users/distiller
我们将测试分成个测试计划。我们进行了快照、单元和 UI 测试。UI 测试是迄今为止最慢的,我们有多项工作来分解它们。
目标是让每个测试有大致相同的执行时间。将它们收集在一个相似的用例下,并提供一个描述性的名称,可以帮助开发人员快速理解失败的原因。
回归测试
在合并之前测试拉请求(PR)的目的是确保现有代码不会受到某种程度的影响。这不需要运行每一个测试;通常,只要定期运行完整集,就可以使用子集来验证更改。
通过使用更多的测试计划,我们分离出回归和 PR 测试。回归测试在 PRs 上有一个可选的保持步骤,以便在需要时可以运行。然后,基于每个团队的时区,在整个工作周安排回归。
scheduled_regression:
triggers:
- schedule:
cron: "0 05,18,23 * * 1-5" # 18:00 NZDT, 18:00 GMT, 18:00 EST, Monday - Friday (Circle uses UTC)
filters:
branches:
only:
- develop
调整回归和 PR 测试的内容可以给你更快的 PR 运行时间,同时仍然保持良好的覆盖率。如果开发人员觉得他们的特性需要的话,他们也可以轻松地运行所有的测试。
贮藏
在该项目中,通过 Swift Package Manager (SPM)为每个版本下载 8GB 数据。这大大增加了构建的时间,所以我们利用缓存来加速它。
在构建步骤中,我们恢复一个现有的缓存,解析包,并为下一个作业保存缓存。解析是必需的步骤,因为它告诉 Xcode 基于新的本地包刷新 SPM。
恢复:
- restore_cache: # To speed up builds we cache the SPM packages and use the resolved file as a hash
key: spm-cache-v4-{{ checksum "Project.xcworkspace/xcshareddata/swiftpm/Package.resolved" }}
解决:
lane :resolve_cached_spm_dependencies do |options|
if options[:xcode_scheme].nil? || options[:derived_data_path].nil?
UI.user_error!("Resolving dependencies was invoked, but an `xcode_scheme` or `derived_data_path` were not provided.")
end
if options[:workspace_name].nil? == false
# Resolve dependencies and point to cache directory
sh("xcodebuild -resolvePackageDependencies -workspace ../#{options[:workspace_name]}.xcworkspace -scheme #{options[:xcode_scheme]} -clonedSourcePackagesDirPath #{options[:derived_data_path]}/SourcePackages")
elsif options[:project_name].nil? == false
sh("xcodebuild -resolvePackageDependencies -project ../#{options[:project_name]}.xcodeproj -scheme #{options[:xcode_scheme]} -clonedSourcePackagesDirPath #{options[:derived_data_path]}/SourcePackages")
else
UI.user_error!("Resolving dependencies was invoked, but a `workspace_name` or `project_name` were not provided.")
end
end
保存:
- save_cache:
paths:
- ./DerivedData/SourcePackages
key: spm-cache-v4-{{ checksum "Project.xcworkspace/xcshareddata/swiftpm/Package.resolved" }}
我们注意到使用缓存在构建时间上有显著的改进。只有当解析文件的内容改变时,例如当更新或添加包时,才需要更新。
结论
通过对 CircleCI 配置的这些更改,我们看到了测试运行时间的显著减少。总的来说,PR 测试的运行时间从 1.5 小时减少到 30 分钟。
我们的管道还可以更快。但是当我们结合以下优势时:
- 减少片状剥落
- 零硬件维护和停机时间
- 对安全性没有要求,如 VPN 等。
- 无需现场重启硬件
我们发现这是一个可以接受的解决方案,并将继续努力实现未来更快、更智能的 CI。
Jonathan 是 Lightspeed 的一名 iOS 开发人员,从事移动开发已经九年了。他对干净、直观的过程感兴趣,并通过代码使生活变得更容易。他总是忙于一个兼职项目,并和家人住在世界科技之都北爱尔兰的海边。
我的分布式团队如何交流,这样就不会留下任何上下文
原文:https://circleci.com/blog/how-my-distributed-team-communicates-so-no-context-is-left-behind/
我在 CircleCI 的团队由七名工程师、一名产品经理、一名设计师和一名工程经理组成,我们分布在世界各地:从美国西海岸到东海岸,然后到塞尔维亚、泰国,最后到日本。通常,我们的总部设在旧金山、钱德勒、坦佩、博尔德、诺克斯维尔、诺维萨德、曼谷、藤泽和秋田。两周前,我们在圣地亚哥的一次面对面团队活动中相遇,我们问自己一个问题:如果我们可以选择,我们会选择成为一个分布在遥远时区的远程团队,还是宁愿至少在一起更近?
答案是:我们不想改变任何事情。必须默认适合跨时区协作的异步通信,这意味着团队中的每个人都有同等的自由和灵活性,可以随时随地工作。我们重视这种自由和灵活性,它们对我们福祉的影响正在使我们成为一个更强大、更有弹性的团队。
我们今年 1 月才开始组建团队。考虑到我们的分布情况,我们从一开始就非常有意识地考虑如何作为一个团队取得成功,在这个过程中我们学到了很多东西。
远程/异步-提示和技巧
这里有一个经过整理的实践列表,这些实践是我们长期以来发展起来的,可以帮助我们作为一个团队跨越时区一起工作。他们中的许多人深受我们从以前的团队中学到的战术的启发,有些是我们根据团队成员的偏好共同开发的。
过度沟通
当我们的团队最初形成时,我们明确同意的意图之一是过度沟通,并且它被证明是极其有用的。一开始,我们是一个分布广泛的团队,大部分成员从未见过面,我们希望过度沟通至少能帮助我们避免沟通不足,并且最多能找出我们需要的沟通水平。
实际上,在日常情况下犹豫不决时,过度沟通会有所帮助,比如:
- 我将要通过直接信息发送给我的团队成员的内容与他们相关吗?我应该写一条消息吗?是的,过度沟通!
- 我发信息的时机对吗?现在是我同事时区的周日晚上!别担心,过度沟通!他们将决定如何以及何时做出反应(“请勿打扰”和“静音”模式是我们的朋友)。
- 我的同事可能已经知道我要给他们写什么,我应该停下来吗?不,过度沟通!安全总比后悔好。
- 我需要离开键盘去给宝宝换尿布,我的团队关心吗?是的,如果可以的话,过度沟通(省略细节也没关系)!
- 我在尿布里找到的东西看起来像 Pantone 3995 我应该让我的团队知道吗?嗯,也许不是那样。
配对/合作
从一开始,我们就担心会意外地开发出沿时区划分的“子团队”,并在寻找防止这种情况发生的方法。我们发现一种有用的方法是鼓励跨时区工作,即所谓的“乒乓”配对。
“乒乓”配对在原理上类似于传统的配对编程,但却是异步的。我们让各自的日程安排来决定节奏,而不是导航/评论其他人实时编写的代码,并经常切换驾驶员/导航员的角色。这仍然保留了通常的结对编程知识共享的好处,同时实际上允许两个以上的人参与这个过程。
为了便于“乒乓”操作,我们发现:
- 将我们正在进行的工作限制为 3 张卡片(团队中的工程师人数,减半,四舍五入)。这鼓励我们在开始任何新的事情之前寻找已经在进行中的票。
- 尽快发布进行中的拉取请求(PRs)。很自然地,除非有人正在积极地处理某项任务,否则任何人都应该能够通读 PR(和其他相关的沟通)并继续处理它。
- 移交正在进行的工作,要么在空闲时间异步移交,要么在人们的工作时间碰巧重叠时通过视频通话移交,尤其是在一天的边缘,一个人的一天即将结束,而另一个人的一天刚刚开始。
闲置使用
Slack 是我们日常团队沟通的重要工具,CircleCI 的许多其他团队也是如此。我们使用它来传达我们的可用性,在需要时请求帮助,协调临时视频通话等。我们有一个团队频道,它对整个公司开放——当其他团队的成员需要我们的帮助时,欢迎他们加入并参与进来。
为了帮助我们驾驭 Slack 中发生的所有不同对话,我们开发了一些有用的实践。我们:
- 使用表情符号来表示重要的信息。特别是当整个团队在 Slack 上过度沟通时,可能很难在一天开始时滚动 Slack 上的所有消息,更不用说度假回来了。为了缓解这种情况并使扫描我们的频道更容易,我们开始在某些消息前添加表情符号,如:
- 📣 or 🔈用于公益广告
- :感叹号:对于重要警告
- ℹ️对于不太重要的信息
- :问题:对于…问题
- 一个自定义的“指向右边的红色大箭头”:状态:休息或结束的表情符号
- 表面在线程中做出的重要决策。一些重要的决定是在松弛线程内部深处做出的(从🧵 emoji 开始);这很容易被忽略,所以我们决定总是试着把重要的信息也发送到主频道。
- 总结视频通话。我们倾向于“挤在一起”,这意味着在进行“乒乓”配对时,我们会加入特别的视频通话,讨论手头的问题或放弃工作。这有时会让人们很难在 Slack 上跟踪这个问题,所以我们试图在电话结束后对电话中讨论和决定的内容写一个快速的总结(从一个可爱的习惯开始:拥抱:表情符号)。这有助于确保人们理解正在发生的事情,即使他们不能同步参与。
会议
由于我们跨越不同的时区,在正常的一周中,我们无法参加会议。但是我们一起享受同步时间,并把它用于更小的群体。以下是我们实现这一目标的几种方式:
- 拥抱异步单口相声。没有时间让我们所有人都打电话,但每日更新很重要。我们为此使用了 Slack messages(表情符号:站立:),现在我们正在试验一个叫做 Range 的工具。
- 定义工作日。可能很难知道“星期三”到底是什么意思,这取决于说话的人(来自哪个时区)。我们默认为“星期三”,意思是“北美星期三”,不管上下文。所以我会说“让我们在周四的回顾会上讨论这个问题”,尽管我在日本工作,对我来说已经是周五了。
- 回顾会的交替时间段。我们的回顾会每隔一周举行一次,既有对美国友好的时间,也有对 APAC 友好的时间,并确保每个人都有发言权,被听到,并能为改善我们的团队协作做出贡献。
- 默认记录会议并做笔记。对于计划和回顾,我们为无法参加的人提供录音(和回顾笔记)。
- 如果有任何“缺失的链接”,安排同步会议我们的工程师在北美和亚洲工作,而我们的设计师却在欧洲工作。每周,我们至少与他和任何其他可以参加的人进行一次同步通话,并为其他人创建录音和笔记。过度沟通。
这些是我们发现的对我们团队很有用的一些东西;你的可能完全不同!你如何让你的团队保持联系?我们很想听听这个问题:发推特给我们@circleci,告诉我们你的建议。
Open Listings 如何使用 CircleCI 快速扩展并安全发货
原文:https://circleci.com/blog/how-open-listings-uses-circleci-to-scale-rapidly-and-ship-safely/
以下是开放上市团队的客座博文:增长总监凯文米勒(Kevin Miller)和首席技术官亚历克斯法里尔(Alex Farrill)。
一.切尔莱奇会议之前的挑战
在开放上市,我们是一个斗志昂扬、充满激情的团队,专注于一个雄心勃勃的使命:让买房变得简单而实惠。我们的产品相当复杂,因为它必须通过购房过程的每个不同步骤来满足购房者的不同需求。没有彻底的自动化测试,就没有实际的方法来支持所有这些用例。
幸运的是,我们从 commit one 就开始认真对待自动化测试。我们在 Ruby 中运行单元测试,测试我们的算法,比如向属性分派代理,以及应用程序如何与我们的 MongoDB 数据库交互;测试我们的 API 响应的 Ruby 功能测试;水豚、幻肢和硒的端到端集成测试;前端 javascript 测试用 Jest 测试我们的 React.js 代码。我们的测试在 Docker 容器中运行,该容器尽可能接近我们在 Amazon AWS 上的生产环境。虽然我们已经有了一个 CI 解决方案,但是随着我们增加更多的开发人员,我们遇到了快速扩展的问题。随着我们的工程团队在短短几个月内从 3 人增加到 8 人,拥有一个更加稳定并且可以随着我们的增长而扩展的 CI 解决方案成为一种迫切的需求。因此,我们的工程团队找到了新的解决方案,幸运的是找到了 CircleCI。
二。解决方案
我们最近的产品挑战是一个完整的网站改造、重新设计和品牌重塑,目的是帮助购房者清楚地了解开放上市的全方位购房服务。
CircleCI 让我们有信心在发布新代码时不会破坏现有的功能。每个月都有超过一百万的独立访问者访问我们的网站,我们不能让我们的重新设计破坏我们为用户提供服务的连续性。
我们网站的大部分流量来自个人属性页,如下所示:
这些页面包括功能丰富的模块,帮助购房者考虑拥有成本,预订即将到来的房屋参观,并下载物业报告。我们的业务非常依赖这些页面上代码的稳定性。这些特性中的每一个都经过了广泛的端到端浏览器测试,确保它在整个堆栈中都能正常工作。
就其本质而言,这些测试可能既耗时又容易出错。CircleCI 让我们并行运行测试,减少了总的构建时间。此外,CircleCI 系统的成熟性和稳定性意味着我们不必花费时间来诊断不是由我们的应用程序引起的故障。
三。CircleCI 如何帮助我们的工程团队发展壮大
在这种规模的重新设计工作中,我们有来自不同作者的多个利益相关者和许多提交。在我们的网站重新设计期间,使用 CircleCI 这样的协作工具,每天至少可以节省一个小时的会议时间,以协调我们工程团队不同领域的工作。
对于我们以前的堆栈,每次我们雇用一名工程师,我们都必须安排一次电话会议,并签署一份额外的年度合同来增加容量。但有了 CircleCI,我们就可以转动一个拨号盘,而不是拿起电话。现在有了他们的性能计划,平台可以自动扩展到我们正在使用的任何容量—转盘会自动转动!
现在我们已经发布了我们的新网站,我们已经开始了在 React Native 中构建应用程序的过程。我们首先构建了一个带有本机控件的简单 webview 版本,现在正在构建新的本机功能。CircleCI 非常棒,因为它允许我们使用 Mac 硬件编写测试。这让我们可以使用团队中每个人都已经熟悉的工具来测试我们的移动应用程序。
CircleCI 帮助我们专注于真正重要的事情:为客户提供特性,而不是编写 CI 工具和争论内部测试基础设施。当您每天运行 100,000 个测试,并且在这种规模下运行时,消除不必要的工作是一个很大的解脱。
因为 CircleCI 与 Docker 集成在一起,我们可以选择在开发中运行 Docker 容器,这是防止错误的一个很好的防线。如果我们可以在两种环境中运行 Docker,那么我们可以确信在部署到生产环境中时不会遇到新的错误。
从情感和团队士气的角度来看,我们已经注意到我们的工程团队成员在合作上的差异。此外,由于作为一个有凝聚力的单位进行协作,我们发布新功能的速度随着时间的推移而加快。
作为一个 3 岁的产品,拥有大量的代码库和团队中的许多新开发人员,CircleCI 具有不可估量的价值。业务需求记录在测试套件中,因此我们可以确信,即使我们很快就有了新的工程师,我们也可以保持我们出色的产品体验。
四。核心优势
最后,我们的重新设计进展顺利,CircleCI 帮助我们顺利部署。如果我向另一个工程团队推荐 CircleCI,我会这样总结它的价值:
-
平台稳定性和正常运行时间
-
并行化工作流的能力可以显著减少测试构建时间
-
不必运行自己的 CI 堆栈意味着不会浪费工程时间来解决非核心业务问题
-
Docker 让即插即用变得超级容易,尤其是如果你已经在生产中运行 Docker
-
能够在本地环境中运行移动应用测试
-
如果您正在快速发展(希望如此),绩效计划可让您轻松扩展!)
GoSpotCheck 如何使用并行测试将构建时间减少 50%| CircleCI
对于那些远离办公室和办公桌在野外工作的人来说,移动应用通常是他们日常工作和公司办公室之间的主要联系。现场机械师、电缆或电话技术人员或饮料销售人员使用的应用程序和服务是必不可少的工具。
总部位于丹佛的 GoSpotCheck 已经成为许多员工的必备工具。该公司的移动应用和云仪表盘帮助 6 大洲 70 个国家的 200 多个企业品牌增强其移动工作人员的能力。它的软件帮助团队完善商品销售,增加销售额,减少劳动力和费用,确保安全和质量,并提高现场的盈利能力。
尽管在三种不同的环境下——web、Android 和 iOS——构建了一个动态产品,GoSpotCheck 的工程团队发现自己不断受到缓慢而复杂的开发周期的阻碍。它的 Ruby on Rails 产品 monolith 有超过 10,000 个规格需要在每次构建之前进行测试,但每次构建都是在一台计算机上运行的,每次构建需要 30 分钟。不仅构建和测试过程缓慢且手动,而且没有流水线——一切都是以一种特别的方式处理的,没有明确的关口,即在将变更推向生产之前需要通过。
GoSpotCheck 的技术运营副总裁 Nick Wilson 解释道:“我们的 iOS 开发人员尤其需要一种有效的方式来提供配置文件、签署证书并将正确签署的版本放入应用商店。“一次只能有一个开发人员对此负责,因此如果不同的开发人员在他们的笔记本电脑上运行构建,他们必须撤销并重新配置。简直是一团糟。”
该团队转向 CircleCI 和一个持续集成和交付流程,这使他们能够建立一个全自动的管道来部署到 web 应用程序、Android 应用程序和 iOS 应用程序。
“这是在石器时代用粗糙的工具工作和在未来工作之间的区别,”GoSpotCheck 的技术运营副总裁尼克·威尔逊说。"每一个提交或者每一个合并拉取请求都可以被立即部署."
特别是并行运行测试的能力,已经将那些 30 分钟的构建减少了一半。这使得该团队平均每天在其 web 应用程序中推出一个新版本。
威尔逊说:“尽管随着我们针对该产品的开发,测试的复杂性和数量不断增加,但使用并发性和拆分这些测试并在多个容器中运行它们的能力使我们能够缩短构建时间。速度是 SaaS 商业游戏的名字。能够定期部署新功能对我们来说非常有价值,这让我们在市场上非常与众不同,也是帮助我们取得成功的因素之一。"
要了解 GoSpotCheck 如何将 CircleCI 用于其 CI/CD 渠道的更多信息,请在 YouTube 上观看我们的案例研究视频。
Insights 团队如何利用 Insights 优化我们自己的渠道| CircleCI
原文:https://circleci.com/blog/how-the-insights-team-uses-insights-to-optimize-pipelines/
在 CircleCI Insights 团队,我们不只是为 CircleCI 用户开发东西,我们也是 CircleCI 用户。真的,没有比使用产品更好的方式来了解你的产品了,Insights 团队也不例外。
几个月前,我们意识到我们的 Insights UI 的管道配置还有很多不足之处。端到端测试减缓了我们的拉动请求,我们花了太多时间等待部署——我们的 P95 运行时间徘徊在 25 分钟左右。对于一个一天部署多次的团队来说,这些数字真的越来越多。
我们花了几天时间重写我们的管道,我们非常高效。投资回报令人震惊——两天的工程工作使构建时间减少了大约 50%。我们的 P95 运行时间已经削减到 12 分钟。更好的消息?每个 CircleCI 用户都可以使用我们使用的工具,我将向您介绍这个过程,希望您可以重复我们的成功。
了解您的工作流程
在你写一行 YAML 之前,知道你在写什么是很重要的。在我们的案例中,Insights UI 是在单个工作流中构建、测试和部署的,因此这是我们调查的起点。要创建工作流程的心智模型,请回答以下问题:
- 每个工作负责什么?寻找试图进行多任务处理的工作,并优先精简这些工作,例如,构建 Docker 映像,对映像进行安全扫描,并将其上传到 Docker Hub。
- 每份工作需要什么?如果你在某个地方上传静态资产,你需要确保这些资产已经构建好了。
- 作业什么时候运行?他们应该什么时候跑?部署了金丝雀的分支可能需要不同于特性分支的一组工作。
能够为这些问题提供清晰的答案将有助于您将一些最佳实践应用到您的工作流架构中,包括编写原子作业以及使用缓存和工作区优化数据流。
编写原子作业
一个写得好的工作很像一个写得好的单元测试:它是原子性的。它只做一件事。其中一个重要原因是原子作业提供了更短的反馈循环。如果您希望能够快速修复故障,您需要能够尽快找到故障源。当一个任务是多任务的时候,这变得更加困难,因为你必须解析可能分布在不同步骤上的输出。
原子作业在未来也更容易重构。有可能在某个时候,您需要在工作流程中间添加更多的步骤,当您现有的所有工作相互分离时,这将变得容易得多。
使用工作区和缓存控制数据流
通常,一项工作取决于另一项工作的产出。例如,您可能想要构建一本故事书并将其发布到某个地方,或者构建一个 Docker 容器并上传到容器注册中心。数据应该总是向下游流动。您的工作流应该从左到右逐步构建;如果有多项工作所依赖的资产,那就需要尽早构建。我们工作流程的第一步是安装 node_modules,因为我们需要 Jest 和 Storybook 包来运行我们的其他作业。
为了正常工作,您需要使用缓存或工作区。这些工具允许你跳过昂贵的过程,除非它们是绝对必要的。
贮藏
您应该缓存任何生成成本高且可能在工作流运行之间重用的数据。如果你使用的是 yarn 这样的包管理器,确保你缓存了那些依赖关系!我们从缓存中提取依赖项大约需要 15 秒,而全新安装大约需要一分钟。我们只需要在添加全新的依赖项时重新安装,这种情况并不常见。
工作区
如果您的数据在每次工作流运行之间都会发生变化,但仍需要在作业之间进行访问,则应该使用工作空间。例如,如果您的测试作业生成了一个覆盖率报告,那么另一个作业将会上传到一个代码分析工具中。
有关持久化数据的更多信息,请查看我们的文档。
利用洞察力确定优化目标
我可能有点偏见,但洞察力是一个非常有价值的工具。任何优化工作都应该从这里开始:您可以识别趋势、长时间运行的作业和不可靠的测试。带上你的侦探帽,看看你的目标工作流程和工作。虽然这篇文章不打算详细介绍测试,但是也值得您花时间查看一下 tests 选项卡。
以下是一些需要注意的事项:
- 缓慢的工作:我认为这几乎是不言而喻的,但是如果一项工作占据了你工作流程的很大一部分时间,那就值得仔细研究了。
- 趋势不成比例变化的工作:使用运行趋势作为基线,看看持续时间和信贷支出的趋势。理想情况下,他们应该以大致相同的速度移动——但在这张截图中,你可以看到我们的跑步增加了 35%,而我们的 P95 持续时间飙升了 500%以上。这是一个巨大的危险信号,它表明您的管道可能无法扩展。
- 片状测试:T2 片状测试不仅会削弱你的团队对你产品弹性的信心,还会极大地浪费时间。我们已经看到测试套件在最终通过之前必须重新运行 3-4 次。
- 慢速单元测试:如果你还没有使用并行化和测试分割,我鼓励你去试试。连续运行一个测试套件所花费的时间等于运行每个测试所花费时间的总和;然而,并行运行测试套件的时间等于运行最慢测试的时间。在并行环境中,专注于加速最慢的测试——运行 30%的速度意味着整个测试套件将运行 30%的速度。
描绘出理想的管道最终状态
在这一点上,我们有足够的信息来进行第一次有意义的改变。我们在这里做的第一件事是绘制出我们想要的最终状态——本质上是我们理想管道运行的可视化。
我建议用笔和纸画一个图表。列出你的工作流程需要做的所有事情,并把它变成原子工作的列表。这些作业中哪些会输出数据,哪些需要输入数据?您可以使用数据流将作业分组到“层”中,任何给定的层都应该只包含依赖于上一层或下一层(或两者都需要)的作业。
在我们的案例中,我们有很多工作试图做太多的事情,它们需要被分解。我们还意识到,我们并没有在所有可以从中受益的地方使用缓存。我们不得不重新安排一些工作,这样数据流才有意义。
这是洞察过程的最终结果:
看着这个图,您可能想知道为什么我们没有选择在测试之前运行 lint 和 typecheck 作业。如果类型检查失败,运行测试就没有意义了。虽然这是真的,但在这种情况下运行测试也没有坏处。这也是一个效率问题,它与数据层的概念密切相关。测试不需要 typecheck 可能输出的任何东西,这就是为什么它们被分组在同一层的原因。
假设 X 是运行 lint 和 typecheck 作业所需的秒数。如果我们将测试进行得更深入,并使它们依赖于那些作业,我们将在失败时节省 X - Y 秒(其中 Y 是失败所需的秒数)。这种方法的缺点是,在每一次成功的运行中,我们可以节省 X 秒,但是没有。这里的要点是,如果你重视效率,重要的是要相信数据流,而不是试图武断地将你的工作分层。
“大改写”
首先,请不要真的一口气重写你的整个配置;这是一个灾难的配方。只是“大的重写”比“许多小的、有效的修改的重写”更容易脱口而出。
“许多小的、有效的变更的重写”
在这次重写过程中,我们做了一些改动,我不会用所有的细节来烦你。然而,我想分享一些最有影响力的,希望它们能启发你找到优化你自己构建的方法。
跳过不必要的半音构件
时间节省:默认分支大约 2 分钟
我们使用一个名为 Chromatic 的工具来确保所有的可视化 UI 更改在部署之前都经过审查。这是我们管道中非常重要的一步,但它需要大约 2-3 分钟来运行,而且并不总是必要的。我们只想在这两个条件都满足时运行这一步:
- 对源代码进行了有意义的修改。如果你的公关只是更新一个 docker 文件,就没有必要在 UI 上运行回归测试。为了跳过这个场景中的色度,我们 grep git diff 来检查在
src/**/*
下是否有任何改变的文件 - 该版本不在默认分支上。我们已经以这样的方式配置了 GitHub,如果一个 UI 更改进入了默认分支,这意味着它已经被审查和批准。在默认分支上,我们仍然上传文件以保存干净的彩色历史,但是批准是自动的。
chromatic:
executor: ci-node
steps:
- checkout
- restore-yarn-cache
- run:
name: "Generate snapshots and upload to chromatic"
command: |
# Get the diff between this branch and the default branch, filtered down to src/
export CHANGED=$(git diff --name-only origin/main... | grep -E "src\/.*\.(ts|tsx)$")
main() {
# Skip completely if not default branch AND no changes
if [ -z "$CHANGED" ] && [ "$CIRCLE_BRANCH" != "main" ]; then
echo "No components changed; skipping chromatic"
yarn chromatic --skip
exit 0
fi
# Auto accept on default branch, they have already been approved
if [ "$CIRCLE_BRANCH" == "main" ]; then
yarn chromatic --auto-accept-changes
exit $?
fi
# Otherwise, run chromatic
yarn chromatic --exit-once-uploaded
}
main "$@"
重构构建-部署-静态和缓存 Next.js
节省时间:每次构建大约 5 分钟
我们使用 Next.js,这意味着我们必须构建静态文件并将它们上传到 CDN 以使用服务器端渲染。然后使用 Next.js 构建来构建 Docker 映像,对其进行 CVE 扫描。如果我们正在部署,这个映像也会上传到容器注册中心。
如果我们正在部署,我们只需要上传这些资产,但我们希望对每个 PR 执行安全扫描,以便我们可以尽快捕捉漏洞。在重构之前,所有这些东西都是耦合在一起的,我们做了很多不必要的工作。
build-and-scan
(每次构建):这从零开始构建我们的资产,并执行安全扫描。build-and-deploy-static
(仅部署):这项工作将从头开始(再次)构建我们的资产,并上传它们。
我们进行了两次构建,并上传了不需要上传的资产。更糟糕的是,我们意识到我们没有缓存下一个. js 版本。
你可能想知道我们怎么会忽略这样的事情这么久。答案是“协作”和“代理”的混合体。在 CircleCI,我们的工程团队有很大的自由,包括以他们认为合适的方式配置他们自己的管道的自由。
在这次重构之前,我们使用的是内部维护的 orb,但是缺乏明确的所有权。随着时间的推移,贡献 orb 资源的工程师数量增加了,但是所有权的缺乏意味着 orb 的责任不明确。它最终有机地成长为试图迎合太多团队的东西,其中大多数团队都有非常不同的需求。
我前面提到的同样的自由也意味着我们有能力用我们自己的定制配置替换 orb。我们接受了 orb 提供的那两个作业,并用更小的原子作业替换它们:
build-next-app
(每次构建):我们确保在这里实现 Next 的构建缓存功能。build-and-scan-docker
(每次构建):该作业使用下一次构建来创建我们的 docker 映像并执行安全扫描。deploy-static
(仅部署):上传前两个作业的输出
如果你想了解更多关于缓存的知识,请查看我们的文档。
Cypress 测试的并行化
节省时间:每次构建大约 10 分钟
我们使用 Cypress 来运行我们的前端端到端测试。在重构过程中,我们意识到两件事:首先,我们没有缓存 Cypress 二进制文件,这意味着我们每次都必须重新安装它。其次,我们没有并行运行这些测试!
我们开始使用柏树球来运行我们的测试。以前,它们在 Docker 容器中运行。现在,我们缓存 Cypress 构建,并使用与 Cypress 测试文件数量相等的并行度值。
- cypress/run:
name: cypress
executor: cypress
parallel: true
parallelism: <<pipeline.parameters.cypress_parallelism>>
requires:
- dependencies
pre-steps:
- checkout
- restore-yarn-cache
- restore-cypress-cache
- run:
name: Split tests
command: 'circleci tests glob "cypress/e2e/*" | circleci tests split >
/tmp/tests.txt'
- run:
name: Install cypress binary
command: yarn cypress install
post-steps:
- save_cache:
paths:
- ~/.cache/Cypress/
key: cypress-{{arch}}-{{checksum "yarn.lock"}}
- store_test_results:
path: 'test-results/cypress.xml' # cypress.json
- store_artifacts:
path: cypress/artifacts # this is in cypress.json
no-workspace: true
yarn: true
start: yarn start
wait-on:
'-c .circleci/wait-on-config.json
http://localhost:3000/insights/healthcheck'
command: yarn cypress run --spec $(cat /tmp/tests.txt) --config-file cypress.json
在我们的文档中找到更多关于并行化的信息。
验证您的新管道
一旦你完成了重写管道的过程,你可以使用洞察力来验证你所做的改变已经产生了积极的影响。如果你访问重写的工作流程的洞察,你会看到我们的 P95 持续时间有明显下降的趋势,我们的成功率也有所提高。
还可以将您的项目与您组织内的其他类似项目进行比较。从主洞察页面,您可以使用项目下拉菜单选择要比较的项目。这项工作最大的验证是当我们意识到 Insights 的运行次数是类似项目的两倍多,而我们的总持续时间不到一半。
结论
希望我已经成功地让您相信,在团队的管道配置上投资是非常值得的。这可能看起来令人生畏,但是如果你使用“许多小的、有效的改变”来小块地接近它,这是非常可行的。
记住:使用洞察力来帮助你确定需要改进的地方。从那里,了解您的工作流程,保持您的工作原子化,并控制数据流。如果你记住这些事情,你会发现做出微小而有意义的改变是非常容易的。归根结底,这就是构建软件的意义所在。
Insights 团队的目标是让您的团队能够做出更好的工程决策。如果你想在 Insights 上看到什么,我们希望你能把它贴在我们的 Canny board 上。
自动化并保护您的移动开发渠道| CircleCI
移动应用不同于 web 应用,需要专门设计的工具来满足开发、安全和 DevOps 团队的需求。组织可以通过优化流程和安全烘焙来加速移动应用程序开发,这可以通过使用 CircleCI 和 NowSecure 来实现。作为 CircleCI 的长期合作伙伴,NowSecure 很高兴成为 CircleCI 的技术合作伙伴,与我们自己的 orb 合作注册。
CircleCI 为移动应用 DevOps 团队提供了许多关键的移动特定功能,首先是跨平台执行环境支持,以在相同的配置和提交下运行多个平台(用于构建桌面、Android 和/或 iOS 应用)。对于 iOS 移动应用程序开发人员来说,CircleCI 包括通过浪子匹配进行代码签名、iOS 证书和预置描述文件管理、通过家酿和 iTunes Connect 部署和管理进行 iOS 依赖管理,以及与 Hockey App、Crashlytics 和 TestFairy 的测试版进行服务集成。
NowSecure AUTO 专为移动应用程序安全测试而打造,首先对以任何语言或开发环境编写的 iOS 和 Android 应用程序二进制文件进行跨平台安全测试。NowSecure 测试已编译的移动应用程序二进制文件中的静态数据、动态数据和代码功能,以确保完全覆盖应用程序并获得高度准确的结果。为了在您的管道中快速流动,NowSecure 提供了快速的自动化后构建测试运行,可在 7-15 分钟内完成,并自动将问题反馈到票务系统,如吉拉。全面的安全测试结果,包括 CVSS 评分结果、开发人员补救说明、详细的工件等,包括中断构建阈值。NowSecure 现在通过我们的 NowSecure AUTO CircleCI Orb 提供与 CircleCI 的直接集成。
让我们看看新的 NowSecure AUTO Orb for CircleCI 如何直接集成到 CircleCI 软件和票务系统(如吉拉)中,为构建和部署安全的移动应用程序提供快速的闭环开发周期。
CircleCI 内部和 NowSecure 集成
因为移动应用程序与 web 应用程序有着本质的不同,所以它们需要有针对性的工具来准确、彻底地测试受到攻击的移动应用程序的行为。NowSecure 自动化移动应用程序安全测试引擎可以在构建过程中全面测试应用程序,并在下游自动生成结果。
如上图所示,NowSecure AUTO CircleCI Orb 插入 CircleCI 平台后构建,并与单元测试、功能测试和 UX 测试解决方案并行或串行运行快速安全测试。
NowSecure AUTO 可以自动测试每一个 CircleCI 构建,并将标签输入到开发人员要解决的循环中。与其他安全测试方法不同,这种 NowSecure + CircleCI 集成对开发工作流没有任何影响,因为不需要学习新的 IDE 插件,不需要追踪静态源代码测试误报,也不需要在测试周期中因发现安全漏洞太晚而导致发布延迟。
将 NowSecure AUTO CircleCI Orb 连接到您的项目非常简单,Github repo README.md 中概述了一步一步的详细信息。请注意,您还需要 NowSecure 汽车移动应用程序安全测试引擎软件的许可证。总结一下这个过程:
- 通过您的 NowSecure 管理屏幕在此生成一个 NowSecure 自动令牌。
- 通过访问https://circleci.com并从左侧选项卡中选择“添加项目”来创建 CircleCI 项目。
- 在 CircleCI 中创建一个上下文,方法是从左侧选项卡中选择“设置”,然后从左侧导航栏中选择“上下文”。
- 配置环境变量。以下是最常见的配置项目:
auto_token
:API 令牌的强制参数。我们建议使用环境变量AUTO_TOKEN
来定义该参数,而不是使用作业参数。这个令牌的值等于步骤 1 的输出。auto_url
:NowSecure AUTO API URL 的可选参数,默认值为https://lab-api.nowsecure.com。auto_group
:如果使用 NowSecure 组访问控制,则配置 group-id 的可选参数。您也可以使用环境变量AUTO_GROUP
来指定这一点。
- 将球体添加到
.circleci/config.yml
中。
示例用法:
version: 2.1
orbs:
auto_ci: nowsecure/ci-auto-orb@1.0.5
jobs:
build:
docker:
- image: circleci/openjdk:8-jdk
steps:
- attach_workspace:
at: /tmp/myworkspace
- checkout
- run: cp apkpure_app_887.apk /tmp/myworkspace/test.apk
- auto_ci/mobile_security_test:
auto_file: /tmp/myworkspace/test.apk
auto_wait: "30"
auto_score: "50"
auto_show_status_messages: "true"
在签入更改后,CircleCI 构建应该启动,您可以看到它运行时的输出,如下面的截图所示。
构建完成后,如下面的第二个截图所示,CircleCI 会自动启动应用程序二进制文件的 NowSecure AUTO mobile 应用程序安全性测试。在这个例子中,完整的测试运行只用了不到 13 分钟就完成了。
在下面的第三个截图中,我们可以看到 JSON 测试结果和生成的工件。每个安全发现的单个标签被自动输入到像吉拉这样的问题跟踪系统。
在整个过程中,不需要人工干预。事实上,许多客户始终以全自动集成模式运行 NowSecure“headless ”,并且从不需要登录 now secure 平台本身。
NowSecure 提供全面的安全测试覆盖
在引擎盖下,NowSecure AUTO 通过集成的行为攻击工具提供自动化的动态 appsec 测试。这有助于确保全面的安全测试覆盖,并具有接近零误报的高度准确性。NowSecure 自动查明开发人员和安全分析师想要防止的安全问题,例如:
- 日志文件或系统文件中的敏感数据无线泄漏
- 不正确/不一致的输入验证
- 弱/不正确的加密
- 中间人攻击或远程代码执行的漏洞
- 证书验证问题
NowSecure 自动提供准确、经验证的测试结果,包括简单明了的问题描述、详细的补救说明和所有相关构件,以加快解决问题(针对开发人员)和行业标准的 CVSS 分数、风险和合规性信息(针对安全分析师)。
通常,开发人员甚至不需要查看安全报告,因为他们消耗自动馈送的吉拉票。下面的屏幕截图显示了报告界面,为开发和安全团队提供了更深入的理解。
NowSecure AUTO 提供了一个丰富的仪表板,可全面查看所有指标、趋势线和关键关注领域。如下面截图中的橙色/红色热图所示,需要重点关注的最大影响安全问题包括 HTTP 上的未加密数据、密钥大小、一系列敏感数据问题、“允许数据备份”问题,以及一个以 root 用户身份运行的应用程序。
使用 CircleCI 和 NowSecure 为安全 DevOps 供电
像 CircleCI 一样,NowSecure AUTO 也可以在云中或内部部署。基于您团队的使用案例,NowSecure AUTO 可以随开发人员和安全团队上传二进制文件或完全自动插入 CircleCI 和其他工具而按需运行。
CircleCI 提供了一个全面的 CI/CD 环境,专门针对移动应用程序开发生命周期进行了调整。将 NowSecure 与您的开发工具链直接集成,腾出时间专注于构建和交付您的用户所需的安全、创新的移动应用体验。
观看我们的网络研讨会 CircleCI 和 NowSecure:自动化和保护您的移动开发渠道,了解更多关于 CircleCI 和 NowSecure 的信息。
阅读更多关于移动应用开发持续集成的信息。
NowSecure 首席移动官 Brian Reed 在移动应用、安全和运营方面拥有超过 15 年的经验,包括 now secure、Good Technology、BlackBerry、ZeroFOX、BoxTone 和 MicroFocus/INTERSOLV 安全地动员财富 2000 强全球客户和政府机构。
如何避免面试过程中的偏见| CircleCI
原文:https://circleci.com/blog/how-to-avoid-bias-in-the-interview-process/
这是骄傲月,在庆祝活动之间,你可能也…需要一份新工作。作为一个代表性不足的少数群体进行面试,无论是因为性别陈述或性取向,还是民族血统,身体或认知障碍,或非传统的专业背景,都可能导致面试过程产生更多的焦虑。面试官能问你什么?你一定要回答吗?你如何判断你正在面试的公司是否是你应该考虑加入的公司?
为了找到答案,我们采访了我们所知道的最好的候选人宣传专家:CircleCI 的招聘团队。他们非常关心减少招聘过程中的偏见,并为你提供了一些建议,告诉你如何为自己辩护,你应该利用的资源,以及如何让面试过程最适合你——无论你在哪里面试。
我怎么知道一个公司是否有好的文化?我可以问工作生活平衡的问题吗?
文化是非常个人化的;没有硬性规定。重要的是找到一种适合你的文化,支持你,帮助你把工作做到最好。你对自己的个人界限和阻碍交易的因素越熟悉,你就能在面试过程中更好地辨别公司文化的重要部分。花些时间弄清楚它们是什么,并把它们写下来,这样你就可以带着它们去面试,并时刻记住它们。
如果你想知道公司是否尊重你的首选代词,并且你觉得这样做很舒服,把它们放在你的 LinkedIn 上,你的简历上,等等。看看谁会联系你。
问福利。例如,CircleCI 为与过渡相关的程序提供 PTO 和医疗保险,并为同性受抚养人提供保险。问问你申请的公司是否有员工资源小组,或者任何你感兴趣的特殊福利。如果你在他们的职业页面上看到一些东西,知道你可以问一下。同样,如果你没有看到它,你可以也应该询问它。
在我加入 CircleCI 之前的最后一轮面试中,我记得我对自己说:‘我应该得到(这个,这个,还有这个)。我在那里设立了标杆。这可能会缩小我的公司范围,但我正在寻找一个能让我成长和发展的地方,并尽我所能成为最好的人。不要害怕这样做(如果你有经济能力的话)。你可能会得到一些真正令人惊奇的东西。 Steph Nys(他们/他们),CircleCI 工程资源公司
你的招聘人员可能会谈论文化,但可能只是从他们个人观察或经历的角度。如果你想知道更多关于团队生活的真实情况,去问招聘经理。问他们这样的问题是完全合理的:“跟我说说你们团队的工作时间。如果被录用,你希望我什么时候开始工作?”
我在 Glassdoor 上看到了一些正面/负面/令人担忧的评论。我应该相信他们吗?
像任何评论网站一样,Glassdoor 上的声明应该被视为一个人——评论者——的经历(也要有所保留)。没有理由不重视或忽略任何一个人的经历,无论是积极的还是消极的——每个人的个人经历都是主观的。如果你看到了特别吸引你注意的东西,不管是正面的还是负面的,你完全可以和你的面试官跟进,找出更多的背景。比如说“我在 Glassdoor 上看到一篇评论提到了 __ 。你能多告诉我一些吗?”一个故事总有不止一面。除了评论之外,Glassdoor 也是一个有用的地方,可以找到关于工资级别和福利的一般信息,但请注意,这些数据是自我报告的,并不总是准确的。如果你正在进入一个新的行业或角色,并且想知道期望得到什么样的报酬,这可能是一个很好的资源。说到补偿…
我必须告诉招聘人员我目前的工资是多少吗?
没有。不,不,你不需要回答这个问题,也不需要回答之前任何职位的薪酬问题。你可以随意说“我不想透露这个”,或者“我希望的工资范围是 _____”也可以说你不知道(专业建议:如果你不确定,你可以说你不知道你想要多少薪水,但是你希望得到这个职位的公平市场价值)
为自己辩护很难,这是需要学习的。如果你对招聘人员感到满意,也帮助他们为你辩护。CircleCI 高级招聘人员 Kacey Aumack(她/她)
你可以问招聘人员该职位的工资范围是多少;他们有义务告诉你。也就是说,任何关于薪酬的问题都应该问你的招聘人员,而不是招聘经理或面试小组的其他成员。他们通常看不到工资级别,也不能给你想要的信息。
招聘人员可以问我关于 __ 的问题吗?
招聘人员不能询问:
- 原产国
- 种族/民族背景
- 宗教信仰
- 能力/残疾状况
- 婚姻或家庭状况
- 性取向
招聘人员会问你是否需要签证相关的支持。这是因为这是一些公司有能力提供的,而一些公司没有。
如果你从这个列表中得到了一个问题,或者任何其他你不想回答的问题,你可以简单地说,“我不想回答这个问题。”
寻找让你感觉良好的公司,让你觉得他们在努力。面试是一个人的过程,所以很多公司都在努力变得更好。他们在面试过程中可能并不完美。如果你感觉到他们正在努力变得更好,这是一个好迹象。事实上,你加入他们可能会有帮助!CircleCI 招聘总监劳伦·奥尼尔
如何成为一名 CI/CD 工程师| CircleCI
去年,我在什么是 CI/CD 工程师中写下了我对 DevOps 生态系统中一个角色的想法。在那篇文章中,我分享了为什么这个角色应该存在的理由,以及我对 CI/CD 工程师应该具备的特征、职责和技能的一些初步想法。
自从最初的版本发布以来,我已经与开发人员和 DevOps 专业人员就我对这个角色的看法进行了许多引人入胜的讨论。这些互动和对话给我提供了大量的反馈。我很高兴地得知,它与我交谈过的大多数人产生了共鸣。
在这篇文章中,我将提炼一些想法,并分享一些过去一年的额外收获。
什么是 CI/CD 工程师?
在我们开始之前,我将简单分享一下我在什么是 CI/CD 工程师?这篇文章关注了这个角色的两个核心要素:特点和职责。
CI/CD 工程师的特征
- 很强的沟通技巧
- 敏锐的分析技巧
- 能够将复杂的流程分解成可理解的组件
- 精通自动化和优化流程
- 能够胜任团队建设和团队沟通策略
CI/CD 工程师的职责
- 制定 CI/CD 原则
- 反复审查和修改 CI/CD 原则
- 维护 CI/CD 工具/平台(如果适用)
- 开发和维护管道配置
- 自动化流程
这些要素仍然适用,经过深思熟虑和多次交谈,新的细节和模式已经出现,证实并支持我的一些想法。在这篇文章中,我将分享这些启示。
新兴的 CI/CD 工程模式
DevOps 和持续交付相关的概念和模式在业界越来越受欢迎。这些概念围绕着安全性、管道优化和整体的 CI/CD 健康。以下是我将讨论的与 CI/CD 工程师相关的新概念列表:
- 安全/开发部门
- 管道优化
- 性能基准
CI/CD 工程师的安全/开发保障
在我最初的帖子中,我建议将与安全相关的职责作为 CI/CD 工程师角色的一部分。随着 DevSecOps 和开发人员友好工具的日益采用,安全责任和流程正在乞求“左移”。这实质上意味着开发人员能够自信地将与安全相关的活动合并到他们的 CI/CD 过程的初始阶段,因此将它们向左移动(朝向这些过程的开始)而不是向右移动(朝向结束)。
CI/CD 工程师可以在安全团队和负责合规/监管要求的人员之间建立强大的沟通渠道。这些沟通渠道在开发人员和安全团队之间产生了有价值的协作,使每个人都能很好地了解关键需求。这些协作还促进了 DevSecOps 原则的采用,使开发人员了解并投资于其他未知的安全实践。
我在下面确定了一些应该发生在 CI/CD 管道的“左边”或初始部分的安全实践。这些很可能由 CI/CD 工程师来定义。这些实践简化了所需的安全任务,并提供了宝贵的反馈循环,防止了在您继续处理最终以失败告终的下游管道段时出现的时间和资源浪费。最好在管道中尽早发现并解决问题。
以下是 CI/CD 工程师可以定义和维护的一些安全实践:
- 漏洞扫描:探测应用程序的安全弱点,这些弱点可能会使应用程序遭受攻击
- 容器映像扫描:分析容器映像的内容和构建过程,以检测安全问题、漏洞或有缺陷的做法
- 法规/合规性扫描:评估对特定合规性要求的遵守情况
还有许多其他的行业标准安全实践通常在发布过程中实现。我上面提到的例子只是 CI/CD 工程师可以与安全和 DevOps 团队合作实施和管理的一些任务,以确保所有安全和合规性要求都是自动化的,并在 CI/CD 管道部分中得到一致应用。
面向 CI/CD 工程师的流水线优化
根据我的经验,CI/CD 管道是以一种设置它并忘记它的方式处理的。不管出于什么原因,团队投入了大量的时间和精力来自动化他们的软件开发和发布过程,结果却在实现之后放弃了这些工作。这主要是因为害怕打扰或破坏对发布软件至关重要的东西。
尽管这是一个潜在的现实,CI/CD 管道意味着代表软件开发和发布过程。因此,它们必须被持续地监控、评估和调整,以确保它们不仅准确地自动化您的软件开发和发布过程,而且高效地这样做。这些管道必须定期重新检查和调整,对于不熟悉所有管道部分的个人来说,这可能是一项艰巨的任务。
这就是 CI/CD 工程师的专业知识能够带来巨大价值的地方。我认为他们是 CI/CD 管道沙皇。他们可以确保管道不被忽视,并有效运行。下面是我的一些想法,让 CI/CD 工程师与适当的团队合作,通过适当地维护和优化管道来增加价值。
管道可重用性
我经历过的并且经常与他人讨论的许多痛点都围绕着管理 CI/CD 工具中的管道配置。这些配置定义了管道,并作为 CI/CD 平台上自动化的执行代码。它们通常用 YAML 、领域特定语言(DSL) 或者其他一些类似的变体来表达。
这些配置中语法通常在功能上受到限制。尤其是在可重用性方面。这主要源于这样一个事实,即语法,像 YAML 一样,是一种声明性的数据结构,而不是一种编程语言。
配置语法导致的限制性代码重用是可以克服的,但需要额外的努力,例如构建可以表示管道段同时封装功能的执行脚本。这些配置可重用性问题在大多数 CI/CD 平台中是常见的,并且通常具有相同的影响:它们非常难以维护。
CircleCI 通过引入配置参数和 orbs 识别并解决了这种配置可重用性,这是一种非常有价值的机制,允许用户轻松打包、维护和实现可重用的管道配置。
不管团队采用哪种配置重用策略,很明显,如果没有专门的维护人员,这些配置重用工作对团队来说会变得非常困难。我认为这是 CI/CD 工程师推动这些工作的绝佳机会。CI/CD 工程师可以对常见的模式和功能有很好的理解,这些模式和功能可以被捕获并封装到有用的动态执行代码中。
大小合适的计算/资源节点
维持高速管道和有价值的反馈循环的一个方面是确保 CI/CD 构建在资源充足的计算节点上执行。在能力严重不足的构建资源上执行管道构建非常普遍,这直接导致了构建速度变慢和反馈循环变长。确定规模适当的计算节点的规格并不是一项简单的任务,这主要是因为要在硬件要求(如 CPU、RAM、网络、磁盘 IO 能力)和维持可接受的构建时间之间取得平衡。技术堆栈和服务之间的硬件需求差异很大,这些细节经常被团队忽略。根据我的经验,这可能是因为团队没有完全了解他们的技术堆栈,和/或他们假设增加的计算节点容量比实际更昂贵。
更强大的计算节点通常成本更高,但成本通常不像大多数团队担心的那样昂贵。我有过这样的经历:通过迁移到一个足够强大的计算节点,某些构建任务减少了一半以上。这个特定的构建作业在一个使用两个 CPU 内核和 4GB RAM 的资源类节点上需要五分钟才能完成。我把资源类升级到 4 个 CPU 核+ 16GB RAM,2.1 分钟完成构建,只多花了几分钱。
在这种情况下,资源类的成本确实增加了很小一部分,但是构建工作的总时间也大大减少了,当考虑到其他费用(如开发人员等待构建完成)时,这创造了更大的节约。通过减少构建时间,开发人员可以更快地获得反馈,并可以在冲刺阶段转移到其他任务上。
CI/CD 工程师可以帮助团队确保构建在资源充足的计算节点上执行。与开发人员和运营商共同承担的许多职责一样,这些看似无关紧要的细节没有得到监控或解决,直到尺寸不足的节点的影响变得非常明显。让一个角色监控和调整这些计算节点问题可以为团队节省大量时间和金钱,同时还可以确保构建时间是最优的,并保持这种状态。
平行
我遇到过这样的团队,他们要么不完全了解他们技术堆栈的所有功能,要么没有充分利用这些功能。例如,我曾经和一些人交流过,他们在管道构建中使用了超过 45 分钟的综合测试套件来完成测试。他们确信这是执行测试的唯一方法。我能够帮助他们利用他们的技术堆栈中包含的一些多线程处理功能。
大多数技术堆栈都具有并行执行代码的能力,这意味着使用计算节点的可用未使用 CPU 内核同时执行多个元素和功能。并行性,也称为并发性,依赖于技术堆栈。它可以是本机提供的,也可以通过利用现有的多线程库或特性来实现。这些多线程功能大大加快了速度。它们可以在堆栈级别使用,而不是在 CI/CD 管道级别使用,在 CI/CD 管道级别,代码按照 CI/CD 配置语法中的定义执行。通过并发执行代码,从一开始就优化了执行时间,并且当应用于管道中的构建作业时,这些构建作业变得更快,而不必调整构建指令中的 CI/CD 配置参数。
在这种情况下,CI/CD 工程师可以帮助团队在核心技术堆栈中启用多线程,并在代码执行时利用通常未充分利用的 CPU 内核。这个角色可以识别效率不高的构建工作,并可以协作实现有效的执行策略。这些策略可以在技术堆栈级别利用多线程,产生利用所有可用 CPU 资源的并发流程实例。
这些优化也可以在 CI/CD 平台构建中实现和执行。CircleCI 还有一个并行的概念,这个概念和我之前讨论的多线程并发没有关系。CircleCI 版本的并行性支持在单个执行器上同时执行多个构建任务。在任何情况下,让 CI/CD 工程师监督这些潜在的优化机会是 DevOps 团队中该角色的另一个理由。
CI/CD 工程师的性能基准
CI/CD 工程师帮助维护和提高管道的一致性和速度,而不损害质量。CircleCI 拥有关于在平台上执行的 CI/CD 构建的大量数据,这些数据使 CircleCI 能够准确地识别、捕获和生成有价值的性能基准。这些性能基准是一些有趣的交付度量的核心,可以被团队用作目标。2020 年软件交付状态 2020:工程团队的数据支持基准报告围绕软件开发团队如何基于以下数据点或基准来衡量他们的绩效:
- 吞吐量:大部分时间或所有时间,工作流运行的数量不如处于部署就绪状态重要
- 持续时间:团队希望工作流程的持续时间在五到十分钟之间
- 恢复时间:团队应该致力于在一个小时内修复或恢复任何失败的运行
- 成功率:90%以上的成功率应该是你对应用默认分支的标准
这四个基准应该被认为是需要监控、捕获和改进的基线度量。每个组织和团队都有不同的特定于业务的目标,这些目标会影响开发效率。控制这种影响取决于扩展和改进底层流程。
CI/CD 工程师的角色绝对可以帮助团队对当前交付状况和 CI/CD 绩效进行有价值的监控和分析。凭借对管道执行和技术专业知识的深刻理解,他们可以合作制定绩效目标和指标,帮助实现和保持追求的结果。
软件开发团队经常对提高开发速度感兴趣,但是与实际的构建活动脱节,而实际的构建活动是影响和控制这些结果的因素。CI/CD 工程师与交付流程密切相关,能够有效地监控和解决出现的缺陷,并在新的或现有基准的基础上进行扩展和改进。他们可以提供近乎实时的监控,使团队能够成功地按照他们期望的速度前进。
结论
我已经展示了 CI/CD 工程师角色的最新观点,并添加了一些新的观点。在这次更新中,我分享了一些新的想法和概念,我认为这些想法和概念可能对这个角色有价值。这些想法集中在安全/开发操作、管道优化和性能基准上,所有这些都是对关键软件交付实践非常有影响的概念。
我很想知道你对这个角色的想法和意见,所以请发推文给我 @punkdata 加入讨论。希望我们能一起把这个想法变成现实。
感谢阅读!
如何为您的团队带来新的 DevOps 工具的五个技巧| CircleCI
将任何新工具引入组织都感觉像是一场艰苦的战斗。很难克服惰性,即使有改善工作流程和更快乐的队友的承诺。任何改变都是困难的,当同事们开始依赖“我们一贯的做事方式”时,改变会更加困难。当你知道有更好的方法时,你如何让你的团队看到光明?
多年来,我们与许多成功地将 CircleCI 引入其组织的个人进行了交谈,因此我们询问了他们对其他采用新工具的人有什么建议。
虽然这些是专门从已经过渡到 CircleCI 的人那里分享的,但它们应该对任何试图思考如何成功引导您的团队进行变革的人有用。
如果您有兴趣尝试 CircleCI 或其他工具,但不确定如何向您的团队介绍它,请继续阅读我们从客户那里收集的关于如何为您的组织带来变革的五个策略。
获得经理的认可。
这里有一个和老板相处的一般建议:不要给她惊喜。当你在尝试一种新的工具或流程时,让你的经理知道可能是个好主意。你永远不要让你的老板陷入这样的境地:别人问他们你正在做的事情,而他们却不知道。这往往不会有好结果。
值得思考的是,你将如何让你的团队领导参与你计划的实验。
例如,考虑这样的对话:“我注意到我们的构建要花 30 分钟来运行,而且我们团队中有很多人在排队。我在考虑在我们正在构建的新微服务上尝试一个新的免费工具。你介意我在空闲时间旋转一下看看是否有效吗?我正在实现我所有的其他目标,所以这只是一个侧面的探索,我们可能会把它带回团队。”
相比之下,“我们的构建需要 30 分钟,整个团队都在浪费时间排队。我们需要停止所有的产品工作,专注于解决这个问题,我希望在我们找到新的解决方案并实施之前,我可以放下所有的工作。”
这并不是说后一种方法不是解决团队问题最有效的方法,但是让别人同意这种方法将是一场艰苦的战斗。他们必须充分认识到这是最迫切需要解决的问题,相信你能解决它,并有政治资本告诉他们的同行特色工作将放缓或停止。那是一个高要求!
你可能会更成功,把它作为一个辅助项目,既能满足你的好奇心,又能帮助团队,还不会让你偏离既定的目标和优先事项。一个好的经理通常会寻找可以答应的事情——他们想给你试验的空间。
尽管如此,最终还是要运用你的最佳判断和你对你的经理可能会如何反应的内部知识来选择最佳的行动方案。如果你知道你的老板肯定会停止任何附带项目,那句关于请求原谅而不是许可的古老格言对你来说可能是正确的。
从小处着手,积累动力。
追求你最大、最复杂的回购,以表明它将适用于你最棘手的情况,这可能很有诱惑力。不要。和任何工具一样,都有一个学习曲线,从小处着手会帮助你最终走得更快。
从小处着手也可能是对你的团队影响最小的,这让你在与他人分享你的学习成果之前可以尝试并建立一个舒适的环境。《财富》100 强企业通常有创新实验室或 X 项目团队,在远离核心业务的地方尝试新想法,这是有原因的。更容易在场外进行实验,很快失败,并在聚光灯外再次尝试一些东西。
对于那些个人理财的粉丝来说,你也可以采取滚雪球的方法,并在这里应用:从你最小、最容易的项目开始,移植到一个新的工具或流程,让它运行起来,然后继续你的下一个项目。虽然这可能不会带来最大的直接影响,但这种势头本身应该有助于您更快地实现最终的采用目标。
想想你团队中最有可能不喜欢这种改变的人。去和他们谈谈。
如果你已经在你的团队工作了一段时间,你可能知道谁会最不愿意接受你建议的改变。(如果你想不出任何人,私下问问一些信任的同事,谁会最讨厌你的新想法)。
也许你的团队中有人负责维护或管理你想要替换的现有工具或流程。或者你的同事在以前的工作场所有过使用某个工具的不愉快经历,每次你提起它,他都会谈论它有多糟糕。
不管那个人的动机是什么,对你认为最抵触的人,最好是直接和直率的。和他们约个时间,或者请他们喝杯咖啡或吃顿午餐,这样你就能得到他们的意见。
你在这次谈话中的目标不是说服任何人你的方式是最好的方式,而是向你的同事学习,理解他们潜在的反对意见。为什么他们会坚持自己的观点?他们想达到什么目的?他们对潜在的变化有什么担心?
考虑说,“我一直在思考我在我们团队中注意到的这个问题,我想探索一些我们可能解决它的方法。我知道你已经花了很多时间思考这个问题,而且你有一些强烈的观点。你能告诉我更多关于你是如何找到他们的吗?”
人们通常对被纳入你的思考,尤其是在早期阶段,以及被询问他们的想法和见解反应良好。与另一个场景形成对比:假设您是团队中某个领域的主题专家或领域所有者,然后您发现其他人(可能不是您的亲密同事,或者可能在不同的团队)正在您的职责范围内打探。如果你从一开始就被蒙在鼓里,你可能会更加恼火,也不太可能合作。
将变化框定为要避免的风险,而不是要实现的胜利。
不要忽视你提议的改变的“原因”。你的团队很忙,你有一百万个优先事项,你可能会超出预算,人手不足,落后于计划。你如何帮助你的团队支持你的想法,并花时间做出改变?
著名心理学家 Kahnemen 和 Tversky 谈到框架偏见是个人如何做出决定的关键驱动因素,特别是不同的论点或框架如何更有可能激励人们做出改变。人类更厌恶损失而不是追求收益,这意味着他们更有动力采取行动以避免负面结果,而不是实现正面结果。
你如何利用这一点?
实际上,如果你把你的建议框定为净收益(“我们会更快,我们的团队会更开心”),你就不太可能成功说服别人加入你的事业。将你的框架改为潜在损失(“我们每个开发人员每天损失 2 小时的生产力,人们非常沮丧,他们打算辞职”)会更有动力。是科学!
这也可以帮助你避免仅仅因为新的、闪亮的或不同的东西就想使用它的刻板印象或误解。
演示、分享和邀请提问。
一旦你的新工具启动并运行,邀请你的团队来看看。许多工程团队都有演示午餐或展示,并告诉个人可以在哪里分享他们一直在做的事情和他们学到的东西。这是一个展示你所学到的东西以及你为什么喜欢它的好时机。
要记住的一件重要的事情是:对于你还没有探索的领域,或者事情没有像你希望的那样进行,要诚实和透明。拥有一份诚实可信的利弊清单,比分享某样东西是“有史以来最神奇的东西”要好得多。邀请公开对话,讨论某个工具在哪里工作得好,或者不好,这是让您的团队集体讨论解决方案的好方法,而不是认为您的演示好得不真实,并寻找错误。
这也是为新流程建立有机动力的好方法:你的目标应该是给你的同事留下一个演示,让他们自己尝试一下。
记住:工具不是银弹。
如果你的团队的目标是转移到持续交付或者采用 DevOps 思维模式,记住改变你的工具可能是一种策略,但是它不是驱动变化的策略。
有时,团队会错误地认为他们可以简单地通过采用一种工具来“完成开发工作”或“开始数字化转型”。虽然改变你的工具可能有助于你实现这一目标,但是通常潜在的组织过程或者团队动态也需要改变。如果你改变你的工具而不改变你的文化,同样的问题很可能会持续存在,只是换了一个新的包装。不要让这阻止你尝试新事物,但是当你考虑什么是现实可行的,在什么时间框架内完成时,一定要记住这一点。
有更多小技巧分享?让我们知道。你是如何改变你的团队的?
在 CircleCI 上建立 Docker 形象
原文:https://circleci.com/blog/how-to-build-a-docker-image-on-circleci-2-0/
在 CircleCI 中,开发人员可以自由组合任意图像,如乐高积木,以创建他们首选的 CI 容器环境。比如 CircleCI 原生支持 Docker 。您可以将应用程序作为 Docker 映像进行构建、推送和部署。CircleCI 使用 Docker 容器中的 Docker 构建 Docker 映像,
在本帖中,我将简要描述如何在 CircleCI 中构建 Docker 图像,包括图像层缓存。
TL;速度三角形定位法(dead reckoning)
在项目的根目录中,在名为.circleci
的目录中创建一个config.yml
:
version: 2
jobs:
build:
working_directory: /app
docker:
- image: docker:17.05.0-ce-git
steps:
- checkout
- setup_remote_docker
- run:
name: Install dependencies
command: |
apk add --no-cache \
py-pip=9.0.0-r1
pip install \
docker-compose==1.12.0 \
awscli==1.11.76
- restore_cache:
keys:
- v1-{{ .Branch }}
paths:
- /caches/app.tar
- run:
name: Load Docker image layer cache
command: |
set +o pipefail
docker load -i /caches/app.tar | true
- run:
name: Build application Docker image
command: |
docker build --cache-from=app -t app .
- run:
name: Save Docker image layer cache
command: |
mkdir -p /caches
docker save -o /caches/app.tar app
- save_cache:
key: v1-{{ .Branch }}-{{ epoch }}
paths:
- /caches/app.tar
- run:
name: Run tests
command: |
docker-compose -f ./docker-compose.test.yml up
- deploy:
name: Push application Docker image
command: |
if [ "${CIRCLE_BRANCH}" == "master" ]; then
login="$(aws ecr get-login)"
${login}
docker tag app "${ECR_ENDPOINT}/app:${CIRCLE_SHA1}"
docker push "${ECR_ENDPOINT}/app:${CIRCLE_SHA1}"
fi
根据项目的不同,一些细节可能会有所变化。如果您想亲自尝试这些步骤,我准备了一个示例项目,您可以使用这个配置文件。
该项目使用 Express 在 node.js 中编写,并简单地返回“Hello World”,用 Jest 和 supertest 进行测试。为了将 Docker 图像(ECR)推送到 Amazon EC2 容器注册表,我使用了一个 Terraform 脚本。
在每一节之后,我将提供它是如何工作的一个细目分类。
顶层结构
version: 2
jobs:
build:
working_directory: /app
docker:
...
steps:
...
在 CircleCI 中,我们可以自由定义每个作业的步骤,包括存储库签出和缓存相关的处理。这给了我们很大的自由,不仅对于 CI 容器环境,而且对于步骤。所有细节都可以在官方文件中找到。
执行者坞站
docker:
- image: docker:17.05.0-ce-git
在本节中,我们定义前面提到的 CI 环境。这个环境是我们的步骤将被执行的地方。
我们想要的是一个安装 Docker 并有 Git 的 Docker 映像。这些要求通过使用docker:17.05.0-ce-git
来满足,它是一个官方 Docker 图像。
当一个图像有后缀“-git”时,意味着 git 是预装的。通过使用这个映像,您可以确保您始终使用最新的 Docker 客户端。
检验
steps:
- checkout
第一步,checkout
,是检查源代码的特殊步骤;这将被下载到由working_directory
指定的目录。
设置远程停靠站
- setup_remote_docker
这一步可以帮助你避免 Docker-in-Docker 问题。事实上,我们正在设置一个与 CI(或主)容器隔离的环境,然后使用远程主机的 Docker 引擎。
安装所需的库
- run:
name: Install dependencies
command: |
apk add --no-cache \
py-pip=9.0.0-r1
pip install \
docker-compose==1.12.0 \
awscli==1.11.76
在这里,我们安装了 Python 、 pip 、 Docker Compose ,以及 AWS CLI 。
在实际项目中,我建议提前在映像中安装这些依赖项。
构建和缓存 Docker 图像
- restore_cache:
keys:
- v1-{{ .Branch }}
paths:
- /caches/app.tar
- run:
name: Load Docker image layer cache
command: |
set +o pipefail
docker load -i /caches/app.tar | true
- run:
name: Build application Docker image
command: |
docker build --cache-from=app -t app .
- run:
name: Save Docker image layer cache
command: |
mkdir -p /caches
docker save -o /caches/app.tar app
- save_cache:
key: v1-{{ .Branch }}-{{ epoch }}
paths:
- /caches/app.tar
这是这篇文章的核心。基本上,我们正在做以下工作:
-
当有以
v1-{{ <branch name> }}
为后缀的缓存时,CircleCI 会将你的目录恢复到/caches/app.tar
。app.tar
是以前构建的 Docker 映像文件。 -
当
/caches/app.tar
存在时,Docker 将加载它,允许我们重用以前构建的图像。 -
当你构建一个 Docker 映像时,你需要指定
--cache-from=<image name>
。 -
我们将保存我们在
/caches/app.tar
中构建的 Docker 映像。 -
最后,我们缓存
/caches/app.tar
以便在下一次构建中重用它。我们使用v1-{{ <branch name> }}-{{ <Unix epoch time> }}
作为缓存键。
我们必须这样做的原因是因为远程 Docker 引擎默认情况下不做层缓存。虽然有一个函数来执行这个层缓存,但是我们必须请求 CircleCI 支持来启用 2.0 公测版中的缓存特性。这也有可能成为正式版本中的付费功能。
您可以参考示例项目的构建历史来查看通过缓存图像层实际可以获得多少速度提升。例如,版本#12 有缓存,而版本#13 没有缓存。在这个例子中,我们看到速度增加了大约 22 秒。
运行测试
- run:
name: Run tests
command: |
docker-compose -f ./docker-compose.test.yml up
对于这个项目,我用 Docker Compose 运行测试,并且测试只在应用程序容器中运行。如果您需要一个数据库容器,使用 Docker Compose 很容易设置一个。
推送 Docker 图像
- deploy:
name: Push application Docker image
command: |
if [ "$ {CIRCLE_BRANCH}" == "master" ]; then
login="$(aws ecr get-login)"
${login}
docker tag app "${ECR_ENDPOINT}/app:${CIRCLE_SHA1}"
docker push "${ECR_ENDPOINT}/app:${CIRCLE_SHA1}"
fi
仅为主分支(在本例中称为“主”)构建 Docker 映像并将其推送到 ECR 存储库。我们从之前安装的 AWS CLI 获取登录信息。在一个真实的项目中,您通常会在推送映像后使用ecs-deploy
进行部署。
结论
CircleCI 允许您使用远程 Docker 引擎来构建 Docker 映像。即使在我的例子中构建速度的提高很小,我仍然知道缓存 Docker 图像层是可以做到的。根据项目的不同,构建速度的提高可能会更大。
阅读更多信息:
Naoto Yokoyama 是一名自由职业的全栈工程师。你可以在 Twitter 、 GitHub 或者他们的博客上与他们取得联系。
如何建立工程师的自信:来自 CircleCI 工程师和高管的建议
每个人的自信都不一样——自信没有一个正确的定义或表达。对一个人来说它是随着时间的推移由成功和失败建立起来的,而对其他人来说自信是自然的,但需要时间的磨砺和磨砺。这也是许多人纠结的事情,需要他们付出大量的努力和自我反省才能驾驭。
这是人类每天都要面对的抽象概念。
我们采访了六位处于职业生涯不同阶段的 CircleCI 工程师,以了解自信对他们意味着什么,以及它如何帮助他们在工作中取得成功。我们发现的一个共同点是,自信是工程师的必需品。这是一个要求,以确保他们不仅建立工作的东西,但他们也有适当的系统,工具和过程,使成功可重复。
“你想要一个基本上相当于工厂的工程系统,”CircleCI 平台副总裁 Mike Stahnke 说。“你在一端输入原材料,从另一端输出已知形状和特性的产品。这是自动化一直让我感兴趣的事情之一,尤其是 CI。这是软件制造的工厂车间。你想要的信心是,我可以做出改变,但它不会改变我在另一边构建的东西的整体形式,它仍然在所有的质量测量范围内。这就是竞争情报的本质:一个自动化的信心收集过程。”
对于 CircleCI 软件工程师 Jacque Garcia 来说,与他人分享知识和解决问题(和拳击)帮助她树立了作为工程师的信心。
“结对编程在那里也确实非常有用,”她说,“想要自己解决某个问题很容易,只需要花上几个小时就能解决。当这个问题很容易被解决的时候,只需要问一个人,“嘿,你遇到过这个问题吗?”"
“在配对之前,我试图真正理解问题所在。当然,也有你完全没有头绪的时候。这也很公平。我认为这也是获得自信的一部分。你通过提问获得自信,并且不害怕寻求帮助。”
虽然不可能给信心下一个统一的定义,但不可否认的是,信心是构建优秀软件的关键。我们希望这些故事能让我们了解其他人在编码时是如何发展、增强和利用自信的。
你可以阅读系列中的其他帖子,从罗布·祖伯、迈克尔·斯坦科、斯蒂格·布劳塔塞特、格伦·梅勒、雅克·加西亚和迈克·马尔克斯。
如何树立工程师的自信第 4 部分| CircleCI
在这个系列中,我们把工程部门的人拉到一边来谈论信心。从技术高管到工程、管理和网站可靠性领域的基层人员,我们都想知道“信心”对他们意味着什么,以及在他们的职业生涯中,信心发生了怎样的变化。你可以阅读系列中的其他五篇帖子,分别是罗布·祖伯、迈克尔·斯坦科、斯蒂格·布劳塔塞特、雅克·加西亚和迈克·马尔克斯。
在这次采访中,我们采访了 CircleCI 的软件工程师 Glen Mailer。我们希望你喜欢它。
你的角色是什么?你在工程领域工作了多长时间?
我目前的角色是一名软件工程师。我已经做了……嗯,我倾向于用开发者这个词,可能有十年了吧?是啊。十年的职业生涯。在那之前我是个业余爱好者。
作为一个开发者有自信是什么意思?
所以当你第一次说到这个的时候,你脑海中浮现的第一件事就是考虑软件测试、发布和部署。这是我最初的想法。然后想了更多,我开始思考提出问题的信心,并参与软件交付的所有方面,而不仅仅是粗制滥造代码。
工具,或者自动化,是如何改变你对代码的信心的?
我认为这都归结于反馈周期。在我的职业生涯中,反馈周期变得越来越好。在某个时候,我意识到“这非常重要”,我开始把它作为一个首要目标。
我认为我对反馈周期的兴趣来自于我曾经是一名 Ruby 开发人员的时候。那是我第一次接触到非常非常快速测试的生态系统。自动运行在一个循环中,你做了一个改变,你点击保存,你得到了 TDD 红色,绿色,重构循环。你真的要确保看到反馈,做出改变,并尽快看到更多的反馈。
在来 CircleCI 之前,你对这些快速反馈周期感兴趣吗?
这是我在加入 CircleCI 之前在不同公司做过的事情,当时我是一名独立承包商。我走访了一些公司,试图帮助他们更好地进行持续部署和迭代交付,首先考虑客户——不要消失一年来生产一个产品和“tada!”让顾客问“这是什么?”
这真的很有趣,你习惯了某些事情是正常的,然后你忘记了对其他人来说什么是正常的。所以,时不时有人会谈论 scrum 或 sprints,我无法理解等待两周来改变我的想法。但在一些地方,他们每季度发布一次,所以进行三周冲刺将是一大进步。我认为,每当我们给出关于软件开发的建议时,我们陈述建议有效的环境是非常重要的。我认为许多人试图给出普遍的建议,我不认为这是一个好主意。
你习惯了某些事情是正常的,然后你忘记了对其他人来说什么是正常的…我认为这真的很重要,无论何时我们给出关于软件开发的建议,我们都要陈述建议有效的环境。
你如何建立对你的团队的信心?你怎么能相信你的同事正在做的工作呢?
我认为主要是关于迭代和可见性。它能够做出一系列微小的增量变化,人们可以在前进的过程中看到这些变化,并感到自己是其中的一部分。你会对如何到达目的地有共同的理解。我认为这真的很重要。
当你停滞不前或者不确定你能达到你期望的结果时,你是如何前进的?
有一点是肯定的,结对编程和循环更多的人。另一件事是想说,好吧,我们能咬下一小块吗?我们能分析一下这个问题吗?我们能重新定义问题陈述吗?或者,我们是否可以退一步说,好吧,我们到底要实现什么?我们的客户实际上想要做什么?也许有一种完全不同的方式来处理我们目前正在做的事情。我认为这是我过去做大量开源支持工作时养成的一种习惯。
我认为,在你制造产品时,了解更多关于我们试图解决的问题和客户需求的背景有助于你做出决策。当你没有这种背景时,你将不可避免地做出许多小决定,并猜测事情将如何进行。但是你获得的背景越多,你就越能理解更广泛的目标是什么,你就越有可能朝着正确的方向迈出一步——我认为这确实会培养很多自信。
你获得的背景越多,你就越能理解更广泛的目标是什么,你就越有可能朝着正确的方向迈出一步——我认为这确实会培养很多自信。
作为一名开发人员,在产品或功能开发中引入客户意见是如何建立你的信心的?
用户研究是我在过去几年中真正投入的事情——这就是我们所说的“这是分析数据所说的,这是所有的反馈,这些是客户遇到的问题领域。”由此,我们可以知道:顾客需要什么?而不是客户想要什么。
这也是关于建立信心,继续问这些问题。幸运的是,我最终找到了一份我认为非常舒适的工作,这样我就可以问一些非常愚蠢的问题——这是一个心理上非常安全的环境,所以我养成了一个好习惯。
我总是会问一个澄清性的问题。即使我非常自信我知道答案是什么,我仍然会经常问这个问题,让演讲者也对其他观众说,只是说,好吧,我们都有这个共同的理解。我记得在一家公司,我问了类似这样的问题:“嗯,我们为什么要这么做?”“我们为什么不这样做呢?”只要愿意抬起头来,坚持下去是一项重要的技能。
我总是会问一个澄清性的问题。即使我很自信我知道答案是什么,我还是会经常问这个问题,让演讲者也对其他观众说
作为一名开发人员,有哪些关键的经历改变或提高了你的信心水平?
我记得几年前,我读了一些关于特性切换的文章,我想“哦,听起来是个好主意。”在那家特定的公司,我们有合理的余地去尝试这类事情,只要我们交付了业务指标。因此,我在系统中加入了一些功能切换——将代码发布到生产环境中,然后查看它在生产环境中的表现,这增强了信心。
在那家公司,我们总是很难处理测试数据。登台从来不是真正的代表,只有生产才是,他们正在开发如何安全使用生产的肌肉。
我想我后来意识到,在以前的公司,我们使用的主要系统实际上是一个 CMS,我们可以在其中放置组件并在页面上移动内容。每当我们构建一个新功能时,我们都会构建一个新组件,然后单独地将它添加到页面上。回想起来,我意识到这是一种功能切换的形式,我们会构建它,将其放在错误的页面上,查看它,然后我们会将其放在正确的页面上。
你得过冒名顶替综合症吗?你是怎么处理的?
如果我说不,我听起来是不是很傲慢?冒名顶替综合症不是我真正担心的事情。但是我确实试着确保我非常小心我的语言。我尽量不做绝对的陈述。就像当我讲述一段经历的轶事时,我会明确表示这是过去发生过的事情——这是我的观点,但基于我的经历形成。我说得很清楚了。当我知道这是事实或是我在研究数据中看到的东西时,我会大声说出来。
然后它又回到这个提供的上下文。我试着说,“我这样想是因为这样”,但我想让别人很容易不同意我的观点,并对我的观点进行建设性的讨论。
在你的职业生涯中,你和自信的关系有没有改变?如果是这样,又是如何做到的?
我认为我在迭代和编写自动化测试方面肯定进步了很多。我从 Ruby 社区学到了很多——想想 BDD 和 TDD。它是理解“我们试图解决什么问题”和“我能写一个测试来陈述我试图解决的问题吗?”我真的用它来驱动我正在写的代码。
你会给年轻时的自己什么建议?
“出货”,我想这是我的建议。我的意思不仅仅是将旧的垃圾投入生产。但是,如果你的目标是将代码发布到产品中,并让它到达用户手中,那么你应该从那里开始逆向工作,找出“我如何安全地做到这一点?”你首先想到的应该是“我如何把它展示在人们面前?”
“出货吧。”你首先想到的应该是“我如何把它展示在人们面前?”……我认为“发运”实际上是您可以采取的最小步骤。你必须试着习惯这种渐进的方法。
我认为有帮助的主要事情是以小增量推出东西——例如,我们将推出一个功能,并将其推广给少数客户。最近,当我们在 CircleCI 上推出秘密屏蔽时,我们在几个内部项目上测试了它,我们发现了一些错误并修复了它们。然后我们把它推广给 1%的客户,什么也没发生。然后是 3%。好吧。后来发生了一些事情——所以我们收集反馈,把使用它的顾客比例降到了零。然后,我们修复了这些错误,并再次尝试。所以我认为“卖掉它”是你能迈出的最小的一步。你必须试着习惯这种渐进的方法。
你还有什么要补充的吗?
我认为 CI 和 CD 完全不同,因此解决的问题也完全不同。但是 CD 是关于一致性的。这是命令。这关乎重复性,关乎速度。而是不要用 FTP 复制三个文件。而 CI,对我来说,就是检查基线。它是“这里有一些你可能已经忘记的事情,电脑可以告诉你。”
我是从“我想这是一个 ThoughtWorks 平台”上读到这个概念的。测试时间预算。所以你说,对,我的预算是五分钟,我最多可以花五分钟来运行我的 CI 渠道。在 CircleCI 上,你可以在五分钟内进行大量的并行处理。这个想法是“我不想等太久,我有五分钟时间,我该如何度过呢?我的时间花在什么东西上最有价值?”如果你试图做真正现实的、生产质量的、用生产质量的数据进行测试,试图抓住每一个小的边缘情况,你不会在那个五分钟的项目中适应它。所以你需要做的是锻炼生产测试的肌肉。
生产过程中总会有错误。因此,如果你把所有的精力都集中在避免这些错误上,当你在生产中遇到错误时,不可避免地你会不知道该怎么办。然而,通过锻炼生产测试的肌肉,不断地、迭代地推出变化,当你遇到大问题时,你会有所准备,因为你每天都在练习所有这些小问题。你将组装好你的架构,这样当有一个 bug 时,它不会使整个网站瘫痪。
通过锻炼生产测试的肌肉,不断地、迭代地推出变化,当你遇到大问题时,你会有所准备,因为你每天都在练习所有这些小问题。
如何建立工程师的自信第 5 部分| CircleCI
在这个系列中,我们把工程部门的人拉到一边来谈论信心。从技术高管到工程、管理和网站可靠性领域的基层人员,我们都想知道“信心”对他们意味着什么,以及在他们的职业生涯中,信心发生了怎样的变化。你可以阅读系列中的其他五篇帖子,分别是罗布·祖伯、迈克尔·斯坦科、斯蒂格·布劳塔塞特、格伦·梅勒和迈克·马尔克斯。
在这次采访中,我们采访了 CircleCI 软件工程师 Jacque Garcia。我们希望你喜欢它。
你的角色是什么?你在工程领域工作了多长时间?
我是 X 队的软件工程师。我已经在 X 队呆了大半年了,但是我现在在 CircleCI 已经快一年半了。
作为一名工程师,自信对你意味着什么?
我从几个不同的角度思考这个问题。一是对我的代码的信心。那么,我有多大的信心相信我正在构建的东西正在做它想要做的事情?另一个是作为工程师的自信。当你谈论某些项目或与其他团队合作时,有一定程度的信心来自于理解团队现在的目的和我们正在做的事情。
当你对自己写的代码有信心时,你能做什么?
我对自己的代码越有信心,我就能更好地帮助其他工程师理解我的代码在做什么。当我对自己的工作充满信心时,我可以问很多问题,也可以回答很多问题,并就哪些事情可以改进、哪些事情进展顺利、哪些事情进展不顺利等进行对话。
我对自己的代码越有信心,我就能更好地帮助其他工程师理解我的代码在做什么。
是什么建立了你对代码的信心?
真正了解我正在做的事情的范围有助于我建立信心。如果我知道我正在工作的特性的范围,那么我就知道我正在工作的局限性。我也了解它所包含的所有不同组件。
如果我在开发一个新功能,会有很多问题出现。我知道数据来自哪里吗?我了解它将如何影响我们的用户吗?我了解它将如何影响其他团队吗?我对该功能的工作有信心吗?所以要回答这些问题,我认为归结起来就是真正思考用户的旅程,在你的团队内部和其他团队之间进行良好的沟通,并编写大量的测试。
作为一名工程师,你如何设身处地为用户着想?
对我有帮助的一件事是思考我可以使用一个功能的所有不同方式,而不是自动驾驶。我认为很多时候,当你在创建一个东西的时候,你可能会以一种有限的方式结束测试。你只是在测试“哦,当我点击它时,它能工作吗?”用户旅程更加复杂。你必须问这样的问题“用户从哪里来到这个地方?”我觉得假装自己真的不明白一切是怎么运作的,真的很有帮助。这是关于对用户的同情。
在你的职业生涯中,自信心发生了怎样的变化?
随着时间的推移,我开始理解如何与用户产生共鸣,以及如何通过与我的同事合作以及从他们的经验中学习来获得对我的代码的信心。
我在这个行业呆的时间越长,我就越了解如何问正确的问题。所谓正确的问题,我指的是那些实际上能帮助我继续努力的问题。所以,我认为建立信心需要很多东西,不仅仅是代码。
我在这个行业呆的时间越长,我就越了解如何问正确的问题。所谓正确的问题,我指的是那些实际上能帮助我继续努力的问题。
工具,或者自动化,是如何改变你对代码的信心的?
我想这真的让我明白了如何减少你的时间。我了解到有很多工具可以帮助你更快地完成工作。我只是相信这些工具会和我一起工作,帮助我解决一些我正在处理的问题。
你如何建立对你的团队的信心?你怎么能相信你的同事正在做的工作呢?
结对编程可能是帮助我树立信心的最大功臣。我认为我们可以从彼此身上学到很多东西,我认为结对可以帮助我做到这一点。与其说是‘哦,让我看看你编码的方式’,不如说是理解你解决问题的方式。
结对编程可能是帮助我树立信心的最大功臣。我认为我们可以互相学习的东西太多了……这是关于理解别人解决问题的方式。
结对对于学习解决问题的最佳实践以及测试和编写代码的最佳实践非常有帮助。编程让我全面了解了做一名工程师意味着什么。这无疑对我的职业生涯产生了巨大的影响。它让我成长得最快。
结对编程在你的团队中是如何工作的?
我认为随着时间的推移已经改变了。我想说的是,当我第一次开始的时候,我非常有意识地尝试和尽可能多的不同的人配对,以获得许多观点。随着我变得更加自信,我开始和当时有空的人配对。我们所说的配对是指,如果我正在开发一个功能,我会在 Slack 上发出一个公开邀请,然后说,“嘿,有人想和我一起开发这个功能吗?”我们可以轮流决定谁开车谁说话。
我的一个同事喜欢尽可能多地实践 TDD(测试驱动开发)。所以当我们结对的时候,我们会练习:“嘿,我写第一个测试,然后你写实现,”然后我们来回切换。它可以是相当活跃的,就真正确保你们在彼此之间切换而言。其他时候,结对可能更轻松,你们一起讨论问题,而不是真正跟踪谁在编码,谁在说话。
当你停滞不前或者不确定你能达到你期望的结果时,你是如何前进的?
结对编程在那里也确实非常有用。想要自己解决某件事很容易,而且要花上几个小时才能真正想明白。当它可以很容易地被解决时,只需要问某人,“嘿,你遇到过这个问题吗?”
在配对之前,我试图真正了解问题是什么。当然,有些时候你完全不知道。这也很公平。我认为这也是获得自信的一部分。你通过提问获得自信,并且不害怕寻求帮助。
作为一名工程师,有哪些关键的经历改变或提高了你的自信心?
参与体育运动真的帮助我建立了对职业生涯的信心——不怕问问题,不怕犯错,不怕尝试新事物和打破代码。在大学里,我参加了竞技拳击,它真的帮助我走出了自我,变得更加自信。这真的是勇气的问题。这是关键——有勇气去做某事。你不必对自己超级自信,只要你有勇气。
这真的是勇气的问题。这是关键——有勇气去做某事。你不必对自己超级自信,只要你有勇气。
从事体育运动也教会了我如何尽早要求反馈,并真正关注反馈。当有人指导你时,你可以接受反馈并将其应用到你的工作中,这会产生巨大的差异。
作为一名软件工程师,同事们的支持也是我成长的关键。他们真的很鼓励人,也很擅长提供一个欢迎的空间,态度是“嘿,如果你不知道问题是什么,没关系,我非常乐意帮助你。”那真的很重要。我真的很幸运成为一个团队的一员,这个团队为我提供了探索、学习和犯错的空间。
我真的很幸运成为一个团队的一员,这个团队为我提供了探索、学习和犯错的空间。
你得过冒名顶替综合症吗?你是怎么处理的?
哦,我一直都有这种感觉。我一直无法摆脱那种感觉。我注意到,每个人似乎都会经历,不管他们在职业生涯中处于什么阶段,不管他们的资历有多高。
我注意到,每个人似乎都会经历[冒名顶替综合症],不管他们在职业生涯中处于哪个阶段,也不管他们的职位有多高。
再一次,对我帮助最大的是拥有一个真正令人鼓舞的团队,但也提醒自己,我永远不可能做到完美,总有一天我不会知道所有事情的答案。
我永远也不可能做到完美,总有一天我不会知道所有事情的答案。
同时记下我能想出一些事情的时间。我们的大脑已经很好地记住了不好的事情。所以,有意识地记录下小的成功有助于应对冒名顶替综合症,并记住这一点,是的,有时你不知道自己在做什么,但有时你会知道。这就是事情的发展方向。
我们的大脑已经很好地记住了不好的事情。因此,有意识地记下小胜利有助于应对冒名顶替综合症
你会给年轻时的自己什么建议?
我要说的最重要的一点是,我每天都提醒自己,不要因为害怕犯错或做错事而停止尝试。无论如何都要努力。成功没关系,失败也没关系,但你要去尝试。我试图将成功重新定义为:“我尽力了吗?”如果我做到了,那么我成功了,如果我没有做到,那么我知道我自己失败了。
我试图将成功重新定义为:“我尽力了吗?”如果我做到了,那么我成功了,如果我没有做到,那么我知道我自己失败了。
同时保持好奇。这种心态帮助我面对挑战,尤其是当我面对陌生的事物时——不要让那种不知道的感觉阻止我。只是用一种更好奇的方式对待问题,“我真的对这个很感兴趣。我不知道解决方案是什么,但我真的很好奇,想弄清楚这到底是怎么回事。”这真的帮助我以不同的方式看待问题。
用更好奇的方式处理问题,“我对这个真的很感兴趣。我不知道解决方案是什么,但我真的很好奇,想弄清楚这到底是怎么回事。”
如何树立工程师的自信第二部分| CircleCI
在这个系列中,我们把工程部门的人拉到一边来谈论信心。从技术高管到工程、管理和网站可靠性领域的基层人员,我们都想知道“信心”对他们意味着什么,以及在他们的职业生涯中,信心发生了怎样的变化。你可以阅读系列中的其他五篇帖子,分别是罗布·朱伯、斯蒂格·布劳塔塞特、格伦·梅勒、雅克·加西亚和迈克·马尔克斯。
在这次采访中,我们采访了 CircleCI 平台副总裁 Mike Stahnke。我们希望你喜欢它。
作为一名工程师,自信对你意味着什么?
我想这意味着你对将要发生的事情有很多可预测性。如果你有信心,当你执行一个动作时,你会非常清楚结果会是什么。因此,可能是,如果我部署了这段代码,我知道它会工作,或者如果我推出了这个功能,人们会购买它。或者,如果我运行这个编译作业,它会工作。如果我挑战某人,我会得到我期望的结果吗?我有信心在某件事情上挑战某人吗?
你能在那儿说得更多吗?
我的意思是,有时候你必须自信才能进行艰难的对话。告诉别人他们不想听的事情或者难以启齿的事情并不总是容易的。这需要一定的信心,这就是为什么你要准备;这就是为什么你要提前考虑或者做笔记。很多时候,人们认为处于领导地位的人是没有灵魂的,他们把人看作电子表格中的细胞。我可以告诉你,基本上与我共事过的每一位领导人都不是这样。任何时候,他们不得不把某人放在绩效计划或类似的事情上,这对他们来说是很难的。
在你的职业生涯中,自信心发生了怎样的变化?
随着我越来越资深,它可能会降低得更多。一部分是因为我是一个非常自大的 22 岁年轻人,一部分是因为真正的知识是知道你什么都不知道。所以当你越来越了解还有什么需要学习的时候。你知道你没有所有的答案,这就是为什么你身边有其他人,或者不同的工作人员专门从事不同的事情。所以我要说,我职业生涯中的许多旅程都像是对我所从事的工作变得越来越不自信,我认为这可能不是大多数人所期望的那样。
我职业生涯中的许多旅程都像是对我所从事的工作越来越不自信,我认为这可能不是大多数人所期望的那样。
你如何处理你不确定的情况?
嗯,我想,“我需要什么来获得自信?”所以我发现自己在问,“X、Y 或 Z 发生的条件是什么,我对这些事情有多大把握?”它更多的是关于使用数据获得信心,以及在更长的时间范围内获得信心。与我做 IC 时最大的不同是,当我做决定时,我可以在很短的时间内判断出是好是坏。可能是一天,也可能是一周。通常不需要太多就能判断出我做了正确的决定或者没有。
现在,如果我在六个月后发现,我会为我必须定期做出的一些决定做得很好。他们中的一些人,花了很多年才明白当时的决定是否正确。你总是利用你所掌握的信息做出最好的决定。但是你没有同样的反馈周期来以同样的速度了解、学习和提高。因此,你必须对此采取更加谨慎的态度,并尝试提前获取更多信息。在这种情况下,错误的影响与说“我进行了代码部署,但没有成功”是完全不同的。我再推一个。酷。”
有哪些关键的经历影响了你的自信程度?
我想最早的一些是在会议上发言的。在一个满是 60 或 70 人的房间里做公开演讲,这些人想听听我对一个话题的看法……这非常令人兴奋。我从来不害怕公开演讲,但是有人想听你对一个话题的看法,这真的很鼓舞人心。
我曾经和一个害怕演讲的女人一起工作,现在她比我更擅长演讲。当时,她正准备给 200 人做一个演示。我说,你只需要知道这些:“你现在谈论的事情?世界上没有人比你更了解这个话题。实际上没有人。所以没有人会问你比你更聪明的问题,因为你已经知道所有的答案。”她后来告诉我,正是这条建议改变了她对自己说话方式的整个看法。
我还认为其他一些时刻,比如一次大的晋升,会非常有益,非常鼓舞人心。当我第一次做导演的时候,那对我来说真的很重要。但我也认为还有其他的东西,比如来自同龄人的尊重。他们听你的吗?你的声音对他们有分量吗?如果是这样,那会激发很多自信,因为你尊敬的人正在听你说话。那你应该知道事情可能进展得很顺利。
当我第一次做导演的时候,那对我来说真的很重要。但我也认为还有其他的东西,比如来自同龄人的尊重。他们听你的吗?你的声音对他们有分量吗?如果是这样的话,会激发很多信心
当你陷入困境,或者不确定你能达到你期望的结果时,你是如何前进的?
通常我会以某种形式的哭泣或恐慌开始。那就真的要看情况了。我通常问的第一件事是,犯错的影响或代价是什么?如果成本很小,那么继续前进,看看会发生什么。如果这是一个巨大的成本,这可能意味着获得更多的专家,吸引更多的人,或更多的合作。任何能得到更多观点的东西。或者,我会问,“我能不能把这件事分成一些小的决定,让我朝着正确的方向前进,而不是一个大的决定?”
你怎么看待对代码的信心?
这是我们都在努力的,对吗?你想要一个基本上相当于工厂的工程系统。你在一端输入原材料,从另一端输出已知形状和已知属性的产品。这是自动化一直让我感兴趣的事情之一,尤其是 CI。这是软件制造的工厂车间。因此,如果我在一端输入比特,在另一端输出软件产品或价值或解决方案,那就太好了。你想要的信心是,我可以做出改变,但它不会改变我在另一边构建的东西的整体形式,它仍然在所有的质量测量范围内。
这就是竞争情报的本质:一个自动化的信心收集过程。
当你对自己写的代码有信心时,你能做什么?
你可以走得更快。你也可以用一种更完整、更全面的方式做出改变。“无副作用”的改变可能是一个更好的描述方式。当你有了好的测试覆盖率,你就可以开始做一些改变,如果一个测试失败了,你就会明白为什么那个测试失败了。在很多情况下,测试最终记录了事情应该如何发生。知道事情应该如何发生是一种罕见的奢侈,我认为这种奢侈还没有得到足够的重视。很多时候,软件的工作方式是偶然的,而不是有意的设计。如果你有测试,那么这个行为至少是有意的,并且被记录在案。
所以如果你有好的测试,你可以重构,把东西拿出来,提取出来,把一个服务分成两个或者把五个服务合并成一个;无论你需要做什么,因为你有信心去改变和塑造你正在做的事情。因此,您可以对应客户需求、规模需求、部署需求或任何其他需求。
我认为这就是信心:它是你能多快做出改变并知道它有效。不是觉得有用,是知道有用。
你得过冒名顶替综合症吗?
当然,但是不经常。我想部分原因是因为我基本上已经得出结论,每个人在任何时候都是冒名顶替者。所以,我们都在同一个竞技场上。每个人对某件事都比我知道得多,可能是很多很多件事。所以每个人都在这里,在他们的位置上工作,因为他们在那里带来价值。当我看着我的同事或我经常一起工作的人时,他们的技能与我不同,我认为这很好。
这绝对是这些年来我给人们很多次的建议。“你可能觉得自己是个冒牌货,但你可以做别人做不到的 X、Y 和 Z,”或者“你可以看到事情以不同的方式发生”。好像他们在这个空间的视野很不一样。他们通常会说这样的话,“我写代码没有这个人写得好。”我会说,“你是对的。这不是我雇用你的原因。”
当我坐在满是首席技术官的房间里,我是一个副总裁,我想,“哇,我属于这里吗?”不可避免地,有些事情我比大多数首席技术官知道得多,有些事情他们比我知道得多。这就是世界运转的方式。
有些艰难的情况会让你说,“哇,我已经无法理解了。”这种情况会一直发生。如果没有,你就没有学到东西。
注册试试 CircleCI 并开始对你的代码建立信心
如何建立工程师的自信第 6 部分| CircleCI
在这个系列中,我们把工程部门的人拉到一边来谈论信心。从技术高管到工程、管理和网站可靠性领域的基层人员,我们都想知道“信心”对他们意味着什么,以及在他们的职业生涯中,信心发生了怎样的变化。你可以阅读该系列中的其他五篇帖子,分别来自罗布·祖伯、迈克尔·斯塔克、斯蒂格·布劳塔塞特、格伦·梅勒和雅克·加西亚。
在这次采访中,我们采访了 CircleCI 高级发布工程师 Mike Marquez。我们希望你喜欢它。
你是怎么进入工程领域的?
我现在的角色是发布工程师。当我刚开始的时候,我不是这样做的。我的职业生涯始于 IT 服务台工作。那是在 2007 年。我做了大约五年,它不适合我。我知道我想在软件方面做更多的事情,更多的是一个系统管理员的角色。所以我离开了那份工作,然后在一家名为 Linode 的公司找到了另一份工作。所以我在那里工作了大约两年半。这就打开了在 CircleCI 工作的大门。
我想这就是我自信的来源。因为我来自一个 IT 支持岗位,你知道,重新制作笔记本电脑的映像,在那个岗位上,我并不真正与代码打交道或与系统互动。因此,从这个角色过渡到 CircleCI 的系统管理角色,更多地使用 Linux 和服务器以及诸如此类的东西。太可怕了。
我认为经历面试过程和所有类似的事情,是一个情绪循环。我很兴奋地申请这份工作,期望很低,然后我开始经历求职过程,我的信心一点点下降。压力太大了,你知道,你必须经历,你知道,通常要经历六七次面试。有代码面试和所有相关的东西。所以很费力。
你是怎么处理的?
对我个人来说,在这种情况下,你必须全力以赴度过难关,你知道吗?我希望我有一个很好的方法来处理它。我是一个容易有冒名顶替综合症的人。所以第一步是意识到你是这样的。你知道,你会有消极的自我对话,你必须尽你所能去控制它。这并不总是一场胜仗,但你必须尝试。我经历了整个周期才得到了在利诺德的工作,然后在切尔莱西我经历得特别糟糕。因为对我来说,感觉赌注更高。我的目标是,一旦我离开以前的公司,就去硅谷的一家初创公司工作。
这是我的目标,也是我非常想要的。所以一旦机会出现,这只是额外的压力——我不想搞砸。这又是一样的东西,除了被放大了。但是得到这份工作…那是有史以来最好的一天。
得到这份工作后对你的自信有影响吗?
这很有趣。我想我仍然有冒名顶替综合症要处理,但现在想到我已经潜入了这家公司。我真的很长时间都有这种感觉。可能老实说,在大约两年半的时间里,我一直有这种感觉,就像,最终他们会抓住我,然后把我踢出去,你知道吗?所以这绝对是一个挑战。
作为一名工程师,自信对你意味着什么?
这是一个非常好的问题。我想我可以这样定义它,你觉得你有解决问题的方法。当你刚开始从事工程工作时,如果有人走到你面前,让你做一些事情,而你对那项技术或那组技术没有经验,这真的会让人望而生畏。但是随着时间的推移,随着您获得更多的经验,您开始对正在使用的工具集越来越熟悉,无论是某种编程语言还是某种管理工具。随着我对工具越来越熟悉,人们开始带着问题来找我,我开始觉得,“如果我不知道答案,我就能找到它。”我认为这真的是关键。但是花了很长时间。
随着我对工具越来越熟悉,人们开始带着问题来找我,我开始觉得,“如果我不知道答案,我就能找到它。”我认为这真的是关键。但是花了很长时间。
在我早期 CircleCI 的某个时候,我刚刚转换了团队,那是我第一次第一次使用 Python。我以前所有的经验都是使用 Linux 和其他工具,它们不像编程语言。所以这是我第一次不得不从零开始构建一些东西,这真的非常非常有压力。我的信心下降得如此之低,以至于有一段时间我实际上是在执行一个绩效改进计划。
那时我说,“你知道,你要做一个决定:要么你崩溃,要么你站出来,把这件事做到底。”所以我选择了后者。
这很有趣,因为很多都是我想象出来的。第二,我说,“你可以做到这一点;去吧,“一切都开始解决了。我想我在三周左右的时间里就被淘汰了。所以这是一个很好的情况,但是我需要一点小小的震动来让系统说,“不,你可以做到这一点。”
工具化或自动化是如何改变你与代码的关系的?
我认为它对我产生了积极的影响。在我们产品的服务器安装过程中,我们一度遇到了一个问题。当时,我们根本没有围绕它进行充分的测试。因此,我们必须编写一个测试框架,让我们可以放心地将它发布给客户。在早期的那一点上,我们处于这样一种情况,我们只是对什么可行和不可行,什么可以修复什么或不能修复什么进行了最好的猜测。这将影响客户体验,因此风险很高。这是我在 CircleCI 开始使用该产品时首先要解决的问题之一。
一旦我们开始开发自动化管道并解决了所有这些问题,它帮助我增强了我们的发布是高质量的信心,这本身就有助于我晚上睡觉。在很多方面,我对质量的信心也帮助了我对自己的信心。因为这样你就知道你不会有担心某样东西质量的压力和烦恼。你可以放松,我认为对我来说保持低压力水平与我的自信直接相关。
我认为你用过的工具和你的自信之间也有关联。在这个行业,有太多的工具需要学习。当我开始的时候,我不得不学习 Terraform,然后我不得不学习 AWS,然后我不得不学习 Replicated,然后我不得不学习 Python,然后我不得不学习更多的代码。你必须适应和熟悉的东西总是越来越多。但其中的一部分是,最终你会达到与 Terraform 和 Kubernetes 或 Docker 一起工作的点,然后你会意识到,“哦,好吧。所以他们只是从这件事上借鉴了一些想法。”
但其中的一部分是,最终你会达到与 Terraform 和 Kubernetes 或 Docker 一起工作的点,然后你会意识到,“哦,好吧。所以他们只是从这件事上借鉴了一些想法。”
所以现在你会自动理解其他一些概念。但这需要时间和经验。
我认为结对对自信也有很大帮助,这取决于你是哪种类型的学习者。我是一个非常注重实践的学习者,所以我可以整天整夜地阅读一些东西,这比你给我看要花更多的时间来理解这个概念。只要有可能,我总是抓住机会配对。我认为这给了你一个机会,让你对一些你可能正在纠结的概念有一个基本的了解。
当你不确定如何前进时,你会怎么做?
我相信我的团队。幸运的是,我身边有一个伟大的团队。如果你足够幸运,身边有一个团队,他们有不同的观点,不同的经验水平,这很好。
如果你足够幸运,身边有一个团队,他们有不同的观点,不同的经验水平,这很好。
尤其是发布工程团队可能是我最喜欢的团队之一。因为我认为我们都有不同的技能组合,它们都以一种方式协同工作,你可以互相依靠,互相合作来完成任务。
我的团队中有一个同事,他知道在 Linux 系统和终端中工作的所有事情。所以如果有任何古怪的命令,他会知道的。所以让他看看我的代码总是很好的,因为我知道他会知道那个小捷径或什么东西来使它变得更好。
但是,如果有一些更高层次的概念让我感到困惑,我的团队中有一个人我可以依靠,他在系统方面有丰富的经验。所以我知道我可以带着问题去找他,他会帮我的。我们还有一个队友是测试专家。拥有一个优秀的团队非常非常重要。这有助于我树立信心。
拥有一个好的代码审查过程是非常重要的。如果我们从更高的层面来谈,拥有一个优秀的 CI/CD 渠道肯定会对你有所帮助。因为对你的工作流程有信心,把代码拿到门外,并且知道它是好的、安全的和可靠的,对士气有好处。很高兴知道,如果你写了一些糟糕的代码,你有一个安全网,它会把你从自己手中拯救出来。
你会给年轻时的自己什么建议?
我想如果我能自言自语的话,我会说,“你现在能做的事情比你相信的要多得多。”我认为这是最重要的事情。我今天在职业生涯中取得的成就超过了我 10 年前的想象。
每当我与年轻的工程师一起工作时,我总是试图让他们知道,在你的职业生涯中,你会有质疑自己或怀疑自己的时候。就像我们拥有处理技术问题的工具一样,你需要一套工具来处理你的情感问题。你必须有信仰。
如何建立工程师的自信| CircleCI
在这个系列中,我们把工程部门的人拉到一边来谈论信心。从技术高管到工程、管理和站点可靠性领域的团队成员,我们都想知道“信心”对他们意味着什么,以及在他们的职业生涯中,信心发生了怎样的变化。你可以阅读该系列的其他五篇帖子,分别是迈克尔·斯塔克、斯蒂格·布劳塔塞特、格伦·梅勒、雅克·加西亚和迈克·马尔克斯。
在这次采访中,我们采访了 CircleCI 的首席技术官 Rob Zuber。我们希望你喜欢它。
作为一名工程师,自信对你意味着什么?
嗯,有对正确性的自信,也有对设计的自信。正确性是:我有足够的信心来交付这个吗?这就是 CI/CD 的用武之地。对我代码正确性的信心实际上在我之外:我已经把它外包出去了。通过请求测试系统来验证它,我可以确信它会工作。当然,我可以增加我的覆盖范围和所有这些事情,这将给我更多的信心。
然后我有信心,我在如何实现一些东西方面做出了正确的选择,在良好的抽象和设计等方面。这是我内心深处的想法。
随着时间的推移你会学到这一点。我认为学习不仅仅是有更多的想法,它是关于识别模式和观察事情如何发展,所以你可以有信心事情会足够好。如果我能接受我对自己正在做的事情足够自信,那么我就能继续下一件事。
学习不仅仅是有更多的想法,而是识别模式,观察事情如何发展
我认为这实际上是建立自信最具挑战性的部分之一。我喜欢谈论风险,知道一些事情是非常重要的,因此,我已经付出足够的努力去做足够的工作或做足够重要的事情。或者知道这是一个至关重要的系统,我会做更多的事情来变得更加自信。
在决策过程中,我们从决策模型的角度来讨论这个问题,我们试图在工程中建立决策模型。影响是什么,影响的范围是什么,扭转决策的代价是什么?在这一点上,你会有不同的观点,你会包括更多的顾问和更多的利益相关者来做出决定。
在你的职业生涯中,自信心发生了怎样的变化?
关于建立模式库,我想了很多。只是一个我可以反思的经验库。我喜欢超级怪异的类比,所以我为此道歉:
想想攀岩。当人们开始在顶绳上攀岩时,他们超级抓地力。比如,“如果我摔倒了会发生什么?”然后你倒下了,你倒下了三英寸。你会想,“哦,这没什么大不了的。”现在我真的可以去尝试一些事情了:我可以跳到另一个点,做一些更大的事情,因为我知道我会落下一英尺。然后你去攀岩,那完全是另一回事,但是你第一次攀岩就意识到,“哦,这其实没什么大不了的。”
所以我认为经历“灾难”[你害怕]实际上是一个巨大的信心建立者,因为你基本上对将要发生的事情感到舒适。在那之前,它是一个幽灵。是对未知的恐惧。但是一旦你经历过,你就会知道,“哦,我们知道如何解决这个问题。这很难,但我们都是聪明人,我们会解决的。”如果你总是试图不失败,那么你永远不会做大事。你永远不会去推动,因为推动往往看起来像失败。
我认为经历“灾难”[你害怕]实际上是一个巨大的信心建立者,因为你基本上对将要发生的事情感到舒适。
就信心而言,工具化或自动化如何改变了你与代码的关系?
它改变了一切。我可以构建一个包装器来测试我想要证明的东西,然后我就可以确定它是正确的。以前,我会将它构建到一个大型复杂系统中,然后尝试找到一个大型复杂的方法来手动完成这件事,并创建所有会导致这段代码得到验证的场景。
把它隔离到我正在做的事情上,这样一个键一个键地敲,我就能知道它是否正确。就对我所构建的东西的信心而言,自动化测试是巨大的。
快速部署让我有信心从某些事情中恢复过来。因此,如果我犯了一个错误,或者如果某些东西进入了生产环境,无论是因为我们发布了一些糟糕的代码,还是因为客户以一种以前没有使用过的方式使用它,我们发现了一个问题,这种快速从错误中恢复的能力——因为我知道我可以修复它,并推动修复,使其真正快速地进入生产环境——这是一个游戏规则改变者,对吗?
当我们开始丰富,吉姆[罗斯]说,“我们应该做连续部署。”我马上说,“这听起来像是有人在部署坏了的时候不需要修理它。不,这是个糟糕的主意。部署是可怕的,我们将整夜不眠,这是非常高的风险,我不想一直这样做,我想睡觉。”然后我读了些书。实际上,就在那一刻,我开始思考风险概况、风险缓解和理解我的行动的风险,通过将大量工作结合在一起,我正在创造更大的风险,这是所有部署挑战的驱动因素。通过将它分成小块,我实际上降低了我的风险,隔离了一个小错误,这将是一个小错误,我们会理解它。
第二天早上我回来说,“这就是我们正在做的。我们正在进行持续部署。”我们开始建立系统来做这件事,并且从不回头。
关于自信有什么最后的想法吗?
嗯,另一件事是建立一些东西,并在同一天把它放在你的客户面前…它创造了…我想说它创造了霸气?突然间,我成了一个做事的人。我对此感觉很好,我知道我有这个能力,因为我知道这是经过测试的。
进步的感觉很充实,给你一种“我擅长我所做的事情”的感觉。我在为顾客修理东西”或“我在制造顾客使用和喜爱的东西。”我认为这是一种非常不同的自信。但这是一种非常强大的自信。我只是对自己和我能实现的事情感觉良好,这让我想做得更多。这让我想变得有效率,这很令人兴奋。那篇论文掩盖了很多问题。当你觉得你可以把事情做完,你在传递价值,你和使命联系在一起。
因此,我认为这可能是我从未回顾持续部署的原因。就好像,我再也不想等着把东西送到顾客手中了,因为那太痛苦了。
你会给年轻时的自己什么建议?
我想说,学习是在失败中进行的。这个问题的有趣之处在于,我认为人们会希望回到过去,从错误中拯救自己,但如果我没有犯下我职业生涯中犯下的所有错误,我不知道我现在是否能够做好我的工作。失败是重要的,但关于失败的关键是反思它们,不是停留在它们上面,而是反思它们,因为在每一次失败中,你都会学到一些东西。
是啊,这是一个奇怪的。我想只是:享受旅程,因为它会很乱,会很粗糙,但这就是你学习的方式。
注册试试 CircleCI 并开始对你的代码建立信心
如何树立工程师的自信第三部分| CircleCI
在这个系列中,我们把工程部门的人拉到一边来谈论信心。从技术高管到工程、管理和网站可靠性领域的基层人员,我们都想知道“信心”对他们意味着什么,以及在他们的职业生涯中,信心发生了怎样的变化。你可以阅读系列中的其他五篇帖子,分别是罗布·祖伯、迈克尔·斯坦科、格伦·梅勒、雅克·加西亚和迈克·马尔克斯。
在这次采访中,我们采访了 CircleCI 的软件工程师 Stig Brautaset。我们希望你喜欢它。
你的角色是什么?你在工程领域工作了多长时间?
我是一名软件工程师。我从 2013 年开始从事软件工程,不,是 2003 年,十年时间过得很快,到现在已经 16 年了。但我起步较晚,我开始时大约 25 岁。实际上,我首先学习成为一名电视修理工,然后意识到我不想那样做,所以我增加了两年的学校教育,以便能够上大学。然后我服了义务兵役(在挪威每个人都服兵役),所以直到 22 岁我才开始上大学。
作为一名工程师有自信意味着什么?
我有点笑了,因为我和冒名顶替综合症斗争过,但我隐藏得很好。在我过去的几份工作中,我的职位足够高,人们会带着问题来找我,并向我寻求许多事情的答案,但我并不总是有信心知道所有的答案。如果我什么都不知道,我绝对会敞开心扉。当我遇到一个我不知道答案的问题时,我会做研究来回答它。
但有一点我意识到了,你不可能什么都知道。我发现,对于其他老年人,我们都意识到你不可能知道所有的事情。有了这种共同的理解,无疑建立了我的信心。
我发现和其他老年人一样,我们都意识到你不可能什么都知道
你是如何接受你并不总是知道答案的事实的?
我想这实际上是从我在一家新公司担任更高级的职位时开始的,在那里,我的部分职责是与其他团队沟通,并与多个团队合作。我认为一部分原因是潜移默化,一部分原因是当时我有了第一个孩子,这也产生了相当大的影响。
作为一名家长,很明显我不知道所有的答案,也没有人真的知道,你知道吗?这也可以转化为其他的东西。我认为这也是一种观点,因为突然之间,工作似乎不再是最重要的事情了。
作为一名家长,很明显我并不知道所有的答案,也没有人真的知道
关于获得视角,我记得我的一个朋友曾经在一家医院担任系统管理员,他去面试时说:“我知道你在这次面试中试图给我压力。这是行不通的,因为在我的工作中,如果我搞砸了,人们就会死去。在这份工作中,人们会丢失他们的假日照片。只是不在一个尺度上。”他确实得到了这份工作。但是,记住这种对挑战规模的观点是很重要的。
工具,或者自动化,是如何改变你对代码的信心的?
激发我信心的一件事是持续集成和持续部署,这是这家公司的宗旨。在我以前的工作中,我们没有持续的整合或任何东西。我们一年发布四个版本,只有 CTO 知道如何发布(不过我们已经解决了这个问题)。这是一家小型初创企业,但一点也没有激发人们的信心。在此之前的工作中,我们也有一个非常大的系统,其中相对较少的发布大量依赖于手工测试,我对那个发布过程一点信心都没有。人们总是对发布感到紧张,现在[使用 CI 工具]我一天要部署多次。
[在我以前的工作中]我们一年发布四个版本,只有 CTO 知道如何发布(虽然我们解决了这个问题)…人们总是对发布感到紧张,现在[使用 CI 工具]我一天要部署多次。
当你停滞不前或者不确定你能达到你期望的结果时,你是如何前进的?
我很乐意提问,我倾向于从[松弛]渠道开始。我很少在 DM 中提问,因为默认情况下我喜欢公开,如果我问了,渠道中的其他人可能也不知道答案,所以他们也可能受益。我可能会首先瞄准我们的团队渠道,除非我知道这类问题有一个特定的渠道,或者我知道我的团队成员不太可能做出最好的回答。
是否需要时间来建立自信,以便能够轻松地在空闲频道中提出问题,或者这是你一直觉得很舒服的事情?
我想我已经相当自信了。我总是试着问问题。我总是先试着观察一点点,这样我就能遵循提问的模式。因此,在我上任之初,我每天都在努力等待时机。不是不想问问题,而是想先试着了解一下提问的文化是什么样的。我想我更倾向于不确定我问的特定论坛在哪里是正确的论坛,但这里还不错。我们有一个相当广泛的工程团队,我们的聊天是大多数工程相关的事情去的地方,所以我真的不在这里苦恼。
作为一名工程师,有哪些关键的经历改变或提高了你的自信心?
关于技术案例,我有一个朋友,也是当时的同事,他鼓励我用 C 写一个虚拟机,这让我大开眼界。
但实际上,大多数关键的经历都不是技术性的,更多的是人际交往。近年来,技术挑战感觉更次要了,但我在过去几年里学到了很多,特别是在我以前的工作中,我学会了如何以同情的方式与人打交道和沟通。在我看来,人仍然比技术上的东西难对付得多。
我认为这是一个迹象,表明我正在变得更好。如果技术不再是挑战,而现在人类是,这可能是一个迹象,表明你的影响范围已经扩大到你可以更多地与人打交道的程度。
如果技术不再是挑战,而现在人类是,这可能是一个迹象,表明你的影响范围已经扩大到你可以更多地与人打交道的程度。
注册试试 CircleCI 并开始对你的代码建立信心
如何用 Packer 和 CircleCI 工作流构建不可变的基础设施
原文:https://circleci.com/blog/how-to-build-immutable-infrastructure-with-packer-and-circleci-workflows/
来自出版商的说明:您已经找到了我们的一些旧内容,这些内容可能已经过时和/或不正确。尝试在我们的文档或博客中搜索最新信息。
HashiCorp 最近宣布他们将放弃 Atlas,并将 Terraform Enterprise 作为独立产品提供给客户。在本帖中,我们将概述如何使用 Packer 和 CircleCI 复制您的 Atlas 管道,并举例说明 Packer 作业配置、AMI 生成、使用 Terraform 管理变更以及在 S3 存储工件。在 CircleCI,我们使用 AMIs 作为不可变基础设施的一部分。能够在我们的持续部署管道中的单点将配置和变更管理应用到 AMI 是非常有益的。不可变的基础设施允许我们以尽可能快且可证明的方式纵向扩展以满足需求——如果我们的扩展请求必须等待供应过程完成,我们将不得不过度供应以处理峰值。
一旦您有了以这种方式生成的 ami,您现在也可以通过使用 Terraform(或 Chef、Puppet 等)等工具将您的网络基础设施移入代码中而受益。).让您的基础设施以代码的形式存在,可以让它受益于作为持续集成和部署管道的一部分的变更管理。
在这个过程的每一步,我们都应该以可审计和可再现的方式进行变更,以生成现在可以根据需要进行测试、验证和部署的工件。管道步骤不再需要同步或紧密耦合。我们还获得了改变管道中任何工具的能力,只要它匹配它生成的任何工件的需求。
既然我们已经讨论了为什么要这样做,让我们来看看如何做。在我们的示例中,我们将引用这些工具:
- Docker,它允许您测试和微调每个打包定义
- Packer,它允许您从一个源配置创建多个机器映像
- AWS 命令行(或类似的)允许您部署新 AMI 的实例
我们将有一个基本 AMI 和一个雪花 AMI,它们的源是基本 AMI。我们还将为两者生成清单 json 文件,并将它们推送到 S3。
我们假设您对 Packer 有一定的了解,并且至少已经阅读了 HashiCorp Packer 入门文档。
基本 AMI 的封隔器配置相当标准,您可以在 https://github.com/CircleCI-Public/circleci-packer.看到完整的配置
下面的例子有几个项目可以使调试和测试您的打包程序配置更容易,例如,我们使用一个inline
provisioner 进行循环,直到我们看到云初始化阶段完成,否则我们可能会在操作系统完全初始化之前安装到操作系统上。
我们还定义了user
变量,包括ami_sha
变量,它将从 Packer 配置的 Git SHA 中获取值。这由 tag_exists() shell 函数用来检查正在生成的 AMI 是否已经存在。
"provisioners": [
{
"inline": [
"while [ ! -f /var/lib/cloud/instance/boot-finished ]; do echo 'Waiting for cloud-init...'; sleep 1; done"
],
"type": "shell"
},
{
"scripts": [
"./base/tasks/baseline.sh",
"./base/tasks/cleanup.sh",
"./base/tasks/debug.sh"
],
"type": "shell"
}
],
"variables": {
"ami_name": "baseline-ubuntu-1604",
"ami_base": "ami-aa2ea6d0",
"ami_sha": "{{env `SHA`}}"
}
供应的实际工作由三个任务脚本控制,它们为 Ubuntu 准备 APT 环境,将区域设置为 UTC(唯一的真实时区),然后执行始终存在的apt-get upgrade
。因为我们在基线 AMI 和中执行这些基本任务,所以当基线 AMI 发生变化时,我们的依赖 AMI 会自动生成,我们的下游 AMI 的任务脚本可以针对该 AMI,这改善了我们的干燥(不要重复自己)态度。通过在我们的 Packer 配置中包含一个Docker
构建器,我们还从 Packer 中获得了不仅生成 AMI 而且生成 Docker 容器的能力。
我们可以更深入地研究 Packer 提供的不同旋钮和杠杆,但他们的文档在这方面做得很好,所以我宁愿深入研究 build.sh 脚本中的“粘合”代码,它使菊花链 ami 成为可能。
您可能已经知道,我们使用 Git SHA 作为我们的标记来识别对 AMI 的打包器配置的更改是否会生成 AMI。在common.sh
中,我们有 get_base_ami() ,它以两种方式寻找基本 ami。首先,它将查看我们是否可以在先前运行生成的 manifest.json 文件中找到它,或者它将在 AWS AMI 列表中查找 Git SHA。如果找到了 AMI,我们可以从 AMI 的标签中寻找 CircleCI 工件 ID。
这样,当基础 AMI 的 CircleCI 工作流中的变化触发了我们的依赖 CircleCI 工作流步骤时,我们能够检索生成的基础 AMI,并将其插入到我们的 Packer 构建中。
Packer 是一个非常灵活的工具,可以通过 CircleCI 工作流的配置定义针对多个环境,这种组合为我们不可变的基础架构创建了一个持续集成和部署管道。通过在 bash 脚本中拥有我们 AMI 一代的“业务逻辑”,可以沿着持续集成管道进行管理,我们已经满足了 AMI 一代的可审计和可自动化变更管理流程的需求。
我希望这个公认简单的例子有助于指出这个工具组合如何将一个重要的过程从繁琐的手动转移到 DevOps 任务列表的自动部分。
如何在远程团队中交流|工程师工具
原文:https://circleci.com/blog/how-to-communicate-on-a-remote-team-tools-and-tips-for-engineers/
沟通很难,远程团队的沟通更难。幸运的是,它在一个分布式团队中可以和在一个集中的团队中一样有效,如果不是更有效的话。这篇文章深入探讨了我们的团队如何应对远程通信的两个最大挑战:理解语气和支持协作框架。
虽然这篇文章是从我作为一名工程经理的角度写的,但所描述的实践和链接的模板对远程团队的任何人来说都是有价值的:它们是我们整个工程组织的人们协作、创意和回顾的成果。
了解分布式团队
超交流对确保人们理解他们同伴的意图大有帮助。在一个团队形成的早期,信任——一个高效团队的标志——刚刚建立起来,这一点尤其如此。为了奠定相互理解的基础,花时间去了解你团队中的每个人,并帮助他们相互了解。
为此,请:
-
进行异步介绍以收集信息并设定期望值。
-
在同步会话中实现这些一致同意的标准。
-
根据团队的意见,根据需要调整指导方针。
请记住,在高度分散的团队中,很难在每个人的日历上找到重叠的工作时间。这个重叠就是同步时间。同步时间是有价值的,应该如此对待。在进入同步交互之前,知道你希望达到什么。利用你的异步时间专注于个人工作,并为同步互动做准备。
异步引入
当你的团队正在形成时,使用异步时间收集信息,设定期望,并允许人们定义自己的界限。
-
确保你熟悉公司现有的沟通期望。踩遍别人的脚趾不是建立关系的好方法。如果你是一个团队的新成员,可以考虑发一条短信,解释你会在学习的过程中问很多问题。如果你使用 Slack,更新你的状态说类似的话。
-
发出一份详细的调查问卷,了解团队需要什么(或者,至少,团队成员认为他们需要什么)。如果你是一名即将加入新团队的经理,我建议你发出一些类似的表格,尽可能多地征求意见,并了解情况。
-
定义团队宣言。尽可能快地写下这篇文章。概括地说,这份文件应该总结出你对存在什么过程的理解,以便整理健康的实践和价值信号。在过去的中,我将此归结为两个部分:
- 人(请确保你熟悉每个人的文章) -我希望队友们互相了解,因为他们生活丰富,有好奇的兴趣,工作之外有优先事项。我表示我真的很关心这一点,首先填充我自己的个人资料,并将每个人的名字列为自己的部分。
- 团队流程(你可以略读,作为参考很好) -我们团队协议中定义的框架很重要,我真诚地希望我们遵循它们。也就是说,为过程而过程不会增加价值;我很高兴我们 80%的时候都能实现我们的指导方针。
要了解我如何围绕异步优先通信、反馈偏好和编程值等主题设置松散的基准,请查看此模板。
-
准备同步时间。在分布式团队中组织面对面交流的后勤工作可能会很困难(尤其是在全球夏令时不一致的月份)。让人们填写一份团队时间表,并提醒他们在团队宣言中填写自己的个人资料。
同步关系构建
同步时间对于团队开发的风暴、规范和执行阶段至关重要。利用这段时间了解您的直接下属,并为团队成员创造相互了解的空间。
请注意,异步通信并没有消失,它与同步通信一起,在您的通信框架中得到进一步的确立(见下文)。
-
最大化你的一对一。通过这个相互了解练习,了解您的报告并推动协调。考虑从这个广泛的集合中抓取一些问题来完成随后的 1:1。
-
及时参加饮水机聊天。远程团队不会在午餐时或走廊上相遇。创造空间和同步时间来连接。这可能意味着用开玩笑的时间来填充会议;这无疑意味着为共同的兴趣创建聊天组(也是异步友好的)。我们有#random、# wordnerds、# keyboards、#babies 和#bread,仅举几例。
-
设置预定配对。随机分配一个配对伙伴,每周轮换一次伙伴,直到每个人都和其他人至少配对过一次。在每场比赛开始时,每组的成员应该在一周内每天安排(尽最大努力)三个小时的配对活动。有时,“尽最大努力”只相当于一个小时的配对。特别是在时区跨度很大的团队中,实际上安排会议可以确保人们能够在工作时间进行联系。
对我们来说,在整个团队进行几次轮换后,人们可以轻松地接触和临时配对。在我们的一次回顾会议中,我们决定停止预定的配对。 -
创建团队频道并分享状态更新。(这也是异步友好的。)我们有一个私人团队频道,人们可以在那里发布各种状态更新:他们上网时的早上好,关于他们正在挑选的东西的笔记,午休时间,热门话题和随机观察(关于“章鱼”复数形式的辩论,以及 Xbox 是否是一个必要的就地避难物品的争论跃入脑海)。
我们使用 JIRA 和 ie,并将看板更新与渠道整合在一起,以及来自 ie 的关于员工 PTO 和生日的每周更新。
建立沟通框架
在远程团队中,信息尤其容易被遗漏。重要的是建立起作为通信强制功能的过程。没有必要跟在试图提取信息和上下文的人后面跑来跑去,让你的过程变得沉重。我们的团队采用受敏捷启发的方法,每两周召开一次会议。
提示:使用异步介绍中收集的可用性来选择会面时间。
知识转移会议
Scrum 风格的方法之所以受欢迎,是因为它们容易奏效。也就是说,在远程团队中,这些经典会议的焦点都有所不同:它们都更倾向于提前梳理信息脱节和错位。
我们的欧洲队友在一天结束时站起来,而我们的西海岸队员在早上站起来。这些工程师在 20 多个小时内不会再次重叠。
-
(每日 30 分钟)。每日签到是我们在任何一天唯一保证的同步时间。我们用 30 分钟来代替 5-15 分钟的会议,这样就有时间适当地交换内容和聊天。我们查看看板,重要的是,站立的领导者分享他们的屏幕,并在每张卡上做更新笔记,作为一种强制调整功能。在跨团队协作期间,甚至在发生事故时,这些笔记经常会派上用场(就像一个写得很好的包含“为什么”的 git 日志一样)。)
将站立会议安排在其他常规团队会议之后,这样你就可以从一个会议直接进入另一个会议,如果时间允许,可以早点结束。
-
策划 (1 小时,每周)。我们在每周周五之前整理我们的积压工作,并建立异步点数扑克,希望每个人都能在我们周二的计划会议上填写。
这使我们能够在计划会议上使用评估作为指标来决定每张卡的适当处理方式。用这个过程梳理出上下文。不要总是要求低年级的人解释为什么他们认为某事会很难。请一位给出高估值的高级工程师分享他们对该领域中的龙的了解。你的目标是揭露信息,而不是人。
在计划结束时,我们下一个专栏中的卡片是按优先级排序的,我们希望它们基本上是正确的,并且是现成的。
-
回顾 (1 小时,两周一次)。这是检查团队流程并决定如何改变以更好地满足团队需求的绝佳时机。我们有一个 Slackbot 提醒,要求人们将主题添加到会议议程中。
由于在 1:1 中提出了适合团队的问题,我通常会向他们提供回顾文档。这些对话引发了更大范围的讨论,比如何时以及如何进行代码评审(在什么情况下要求彻底的检查是可以的?不可以吗?我们如何在不升级分歧的情况下进行反击?)以及配对首选项和电话呼叫升级回顾。
团队成员的问题、顾虑和想法应该尽可能地推动会议的内容。
-
大图 (1 小时,两周一期)。这次会议为产品部门预留了空间,让工程部门了解我们正在做的事情和原因。它应该为团队成员提供更广泛的方向背景,以便:
我们有时会利用这个会议来了解跟踪我们进展的方式。例如,我们的项目经理可能会提供一个细分市场中用户采用的速成班,或者我可能会带领团队向高管展示我们的速度。
根据项目经理和团队的当前需求,这个会议也可以重新安排。这是同步时间的预留窗口。它可以被取消,用于事后审查,或变成站立,有额外的时间喝咖啡或娱乐。
对于上述每个会议,在 Foo 团队会议文档的两周中有更详细的分解,值得浏览一下。它包括关于在邀请正文中包含哪些内容的建议(特别是议程和存储在单个文件夹中以提高可发现性的会议笔记的链接)、许多要问的具体问题的示例和几个模板。
配置您的日历,为您做一些繁重的工作。我使用谷歌日历,并从以下网站获得了大量的里程:
-
加上我的工作时间。此功能通知人们,当他们在我的办公时间之外发送邀请时。
-
打开世界时钟。我的配置为显示加利福尼亚、日本和德国的时间。当我点击日历中的一个窗口时,世界时钟会显示该窗口每个人的当地时间。
-
显示辅助时区。我的配置为显示爱尔兰和加利福尼亚的时间。我目前的团队分布在这些时区。
-
将我的 Pagerduty 轮值添加到我的日历中。除非我被传呼,否则我不想被传呼机通知。我按照我的日历生活,所以这有助于我在没有额外通知的情况下查看我何时待命。
-
将缩放日程安排添加到我的日历。因为我 99.9%的会议都是虚拟的,它们都需要一个会议室链接。这个讨厌配置的扩展在我的日历邀请草稿上放了一个巨大方便的“缩放会议”按钮。
结论
有效的远程沟通需要意向性。通过采用本指南中的实践,挑选适合您的团队的方法,就有可能建立信任的基础和沟通框架,使远程团队蓬勃发展。由此产生的交流将与同处一地的团队的交流相媲美,并且对于上下文共享和信息可发现性来说将是固有的。
寻找进一步的阅读?从每日的混战中了解 pCloudy 的教训。
为持续部署设计服务的 3 种方式
原文:https://circleci.com/blog/how-to-design-services-for-continuous-deployment-3-best-practices/
持续交付的好处在其他地方得到了很好的证明。在这篇文章中,我想分享一些我们在 CircleCI 使用的实践,以确保我们的服务可以安全地持续部署。
我们的堆栈由部署在 Kubernetes 上的服务组成。每个服务主要包含在自己的 git 存储库中,并独立于其他服务进行部署。当我们部署新版本的服务时,新代码由 Kubernetes 一个一个地推出。这意味着在任何时候,都可以同时有多个版本的代码投入生产。
以下是我们发现对我们团队很有效的实践列表。
-
防止部署不完整的代码
-
知道何时部署代码
-
确保消息已送达
1。防止被破坏的代码被部署
一些 bug 确实通过了测试,并被部署到生产中。根据我的经验,单元测试中经常出现的一类错误是(经过良好测试的)软件组件在应用程序的顶层配置或组合不正确。
由于我们使用 Kubernetes 进行部署,我们可以在部署时使用它的强大功能为我们提供额外的安全网,帮助我们从生产流量中捕捉这些类型的错误。
我们的 Kubernetes 设置通常会一个接一个地部署新的 pod。考虑一个运行在 3 个 pod 上的服务。当部署服务的新版本时,一个 pod 开始运行新代码。一旦这个单元是健康的,一个旧单元被终止,第二个新单元被启动。像这样一个接一个地滚动 pod 可以确保我们在部署代码时,在生产中始终有 3 个健康的 pod。如果一个新的吊舱无法启动,Kubernetes 将尝试重新启动新的吊舱,一遍又一遍,而留下其余 3 个吊舱在原地。
我们可以利用这种行为。如果我们对服务进行编码以在初始化期间验证它们的配置,并且没有捕捉到任何异常,那么服务将无法启动,并且,Kubernetes 将阻止该代码版本接收生产中的流量。
例如,假设我们的服务有一个用于连接 redis 服务器的连接池。除了在启动时配置连接池,我们可以从连接池中获取一个连接并运行一个简单的语句,比如ECHO "Hello World!"
,并确保不捕捉任何异常——如果服务失败,就让它崩溃吧!
除此之外,Kubernetes 有两种用于监控 pod 状态的探针——“活性”和“准备就绪”探针。“就绪”探测用于让 Kubernetes 知道服务何时完全启动并准备好接受传入的请求。
Kubernetes 不会将流量路由到 pod,直到就绪性探测报告成功。这意味着我们用就绪探测器测试的应用越多,Kubernetes 就越能保护我们不被部署错误。我最近写了一个新的服务,必须能够与 RabbitMQ 和 AWS S3 通信。通过确保与 RabbitMQ 的连接已连接,并且服务可以在返回成功的就绪探测之前将文件放入 S3,我确信我的服务配置正确。
2.知道何时部署代码
如果全天都在部署新版本的服务,我们必须让团队看到我们的部署。我们一起使用 CircleCI、Rollbar 和 Slack 来确保我们知道代码何时被部署。
我们使用 CircleCI 来构建和部署我们的服务(当然),我们使用 Rollbar 的部署跟踪 API 来跟踪部署( Sentry 也有类似的功能)。我们在每次部署时运行如下脚本:
curl https://api.rollbar.com/api/1/deploy/
--form access_token=$ROLLBAR_ACCESS_TOKEN
--form environment=production
--form revision=$CIRCLE_SHA1
--form local_username=$CIRCLE_USERNAME
这给了我们两个好处。首先,Rollbar 知道我们的发布。这种报告,加上我们快速部署较小变更的 CD 实践,这意味着我们可以轻松地将报告给滚动条的异常与导致异常首次发生的 PR 相关联。
第二个好处是,我们可以启用 Rollbar 的 Slack 集成,每次部署团队拥有的服务时,每个团队都可以在 Slack 中得到通知。
在这里,您可以看到一些松弛的流量,我部署了一个包含 bug 的服务的新版本,紧接着是一个新的异常类的松弛通知。
让这些警报出现在 Slack 中确实有助于我随时跟踪谁在部署。
3.确保消息得到传递
我们在 CircleCI 大量使用 RabbitMQ 进行服务间的异步通信。典型的消息类似于运行特定项目构建的指令。
我们在生产环境中运行的任何服务都可能随时被终止,危险在于服务可能会消耗消息队列中的消息,并在有机会采取所需的操作之前被关闭。这与消息丢失具有相同的效果。考虑到这一点,我们推迟确认收到消息,直到我们执行了所需的操作。
在运行构建的情况下,这意味着我们将消息出队,在数据库中创建一个记录来表示构建,然后确认收到消息。现在的危险是,在数据库中创建记录之后,但在确认消息之前,服务可能会被终止。如果发生这种情况,RabbitMQ 会将消息重新排队,并再次尝试传递到队列的另一个使用者。
这导致消息可能会多次到达,并且消息可能会无序到达。
在我们的示例中,如果运行构建的消息被重新交付给第二个消费者,那么该构建的记录将已经存在于数据库中。为了检测这一点,我们需要在每个消息中包含一个惟一的标识符,可能是一个构建 ID。我们可以将这个构建 ID 和惟一性约束一起添加到数据库的构建记录中。这种约束使我们无法在数据库中创建多条记录。
从 RabbitMQ 消费时,我们使用以下模式:
我们确保所有的交换和队列都被声明为持久的,并且禁用自动删除。我们确保标记为持久的消息。我们在队列消费者中禁用消息的自动确认,而选择手动确认或否定消息。我们为消息添加了一些惟一的 ID 或幂等键,这样消费者就可以在需要时删除消息中的重复项。将去杜平消息的责任传递到尽可能远的下游,使我们的服务尽可能简单。
结论
在设计服务时,预先考虑 CD 过程以及它将如何影响您的代码是值得的。部署小的变更,并且尽可能频繁地部署。使用您的部署工具来进一步降低风险。请注意旧的 pod 的终止以及新的 pod 的部署,并注意确保您的飞行消息被可靠地传递。
通过使这些实践成为你工作流程的一部分,你正在采取措施使你的连续交付过程尽可能的平稳和安全。
利用 Docker 和 CI/CD - Kubernetes | CircleCI 进行漏洞管理
原文:https://circleci.com/blog/how-to-do-vulnerability-management-with-docker-and-ci-cd/
在软件包、软件库、操作系统和基础设施中不断发现漏洞。漏洞管理是对软件漏洞进行扫描、分类、优先排序和修补的持续过程。为了稳定和安全,所有现代技术堆栈现在都需要这种周期性的维护和更新。
这是安全性遵从的核心方面之一。在过去的几年里,CircleCI 通过了 FedRAMP 认证和 SOC 2 Type II 合规性,这两项认证都让我们与需要我们漏洞管理流程细节的审计员进行了配对。
虽然漏洞管理是一项绝对必要的基本安全实践,但它通常也是乏味且重复的。这使得它成为自动化和优化的首选。构建足够严格的流程以满足审计员的要求,而不增加我们团队和工程组织的大量开销,这是一个有趣的挑战。
从更个人的角度来说,当 Docker 的 DevSecOps 好处最终为我所用的时候,我就完成了这个挑战。
在这篇文章中,我将向您介绍我们开发的漏洞管理流程,该流程旨在满足审计人员的要求,并与我们团队对 CI/CD、Docker 和 Kubernetes 的使用保持一致。
使用 Docker 技术堆栈打补丁
一点背景:CircleCI 的栈是基于 Docker 的。已经有许多文章讨论了这与传统的基于服务器的架构有何不同,以及这如何影响开发和开发。它还会影响安全性,尤其是对这个帖子来说,影响漏洞管理。
Docker 镜像是不可变的,包含自己的基础设施包和库,这意味着你不能在传统意义上“给服务器打补丁”来“修补”一个。取而代之的是,创建并部署一个具有更新的依赖关系的新映像,并淘汰旧映像。
由此得出的第一个推论是,修补将导致更多部署,映像所有者和 SRE 团队需要了解并能够处理这些部署。我们利用现有的稳定管道进行持续部署,这意味着额外的部署对我们的运营影响极小。
其次,Docker 可以将修补的维护成本分散到更多的工程组织中。在传统的基于服务器的环境中,管理员或 sre 维护服务器并部署补丁程序。在 CircleCI,开发团队负责维护他们的 Docker 映像,因此也负责为它们应用安全补丁。一些开发团队可能需要适应与他们使用的 Docker 映像相关的安全维护工作。
第三,许多法规遵从性专业人员和审计人员不太熟悉这种技术体系的工作方式及其对漏洞管理的影响。留出时间与他们一起了解这些工具如何影响修补流程非常重要。
草拟一份计划
安装漏洞扫描器本身并不能保护任何东西。与所有安全工具一样,为了获得任何好处,这些工具需要应用到我们的系统中。
当我们开始这个过程时,我们知道我们的计划会是这样的:
- 了解实际情况有多糟糕,并在运行中获取一些高优先级补丁。
- 开始为拥有 Docker 图像的团队提供更紧密的反馈环。
- 围绕票据生成和报告重新审视工具和构建自动化。
- 找到一种方法来帮助团队优化和调整他们的修补流程。
贯穿整个工作的一个核心原则是使用工程团队每天都在使用的工具和界面向他们提供反馈:这是一种比使用基于分心的方法(如 Slack、提醒、电子邮件、会议和报告)更有效的方法。
通用起点:电子表格
我们需要做的第一件事是掌握项目的规模和范围,并能够对原始数据进行排序和过滤,以了解我们的情况。
所以我们从许多项目开始的地方开始:电子表格。
我们跑了。csv 导出到电子表格中,添加了用于汇总的公式和一些简单的 AppScript 代码,以进行一些数据清理和协调。我们希望了解当前在我们的实时系统中运行的不同映像和容器,它们有哪些漏洞,以及存在哪些修补节奏;只是在制作任何门票或与任何开发团队交谈之前已经存在的东西。哪些服务有正式的所有者,我们需要为哪些服务寻找所有者?来自工具的数据是什么样的?对我们来说,首先在电子表格中手动查看这些数据是很重要的,这样当我们自动化时,我们就能理解来自扫描仪的数据。
这一步提供了很多细节,让我们对数据中的一些不一致和复杂之处有了初步的了解。另一组重要的信息是没有列出任何官方团队所有者的图像和容器的数量。
然后是分配票证的时间,首先关注具有关键漏洞的映像。我们手动生成第一轮门票,并将其分配给各个团队。因为一些图片没有列出所有者,我们做了一些有根据的猜测,然后观察这些门票是否被转移到其他球队。
收到这些门票的一些团队不习惯从其他团队获得门票,更不用说从安全团队获得门票了。起初我们遇到了一些阻力——开发团队以前没有负责 Docker 映像维护的任务,他们担心这会花费多少时间。我们与这些团队合作来帮助部署初始补丁,这给了我们一个机会来讨论打补丁的重要性,以及它将如何成为一件更常规的事情。
在此阶段发生的另一组对话是与我们的审计人员进行的。在推出我们政策的第一稿后,我们意识到我们的修补时间表太激进了(事实证明审计员已经想到了这一点,但没有推后)。开发团队跟不上。我们意识到,制定合理的政策并付诸实施比过于激进和不断制造例外要好。我们与我们的审计员合作,将政策更新到现实的水平..对于我们来说,这是关于我们的过程成熟度的重要一课。一旦我们有了可重复的过程,我们可以在以后收紧时间框架。
我们在这个阶段学到的一件事是避免完美。如果一个特定的团队处于水深火热之中,一张票在几个团队之间被踢来踢去,或者一个特定的补丁出现了技术问题,不要阻止自己。在补丁和团队中尽你所能取得进步。
使用 CI/CD 划分和自动化工作负载
我们取得了可以取得的初步进展,并进入了下一阶段。这是导致服务定期修补的最大变化。这也是作为一名开发人员,Docker 的好处真正吸引我的地方。
在传统的基于服务器的基础架构中,测试环境独立于生产环境,这些环境需要独立的修补程序和更多基于任务的开销来发现是否有任何特定的修补程序导致问题。
因为 Docker 映像在一个明确定义的部署单元中包含了它们的软件依赖关系,所以扫描 CI/CD 管道中的映像变得很简单。通过包含软件依赖性的自动化测试,可以使用现有测试快速试用和验证补丁。
通过将其集成到 CI/CD 管道中,漏洞修补将不必是我们每个月都要做的一件大事。它将被融入我们发布软件的方式中。
对于那些计划在你的团队中采用这种方法的人来说,要知道这首先会引起痛苦。即使你的团队在 CI/CD 方面很棒,任何时候你在你的构建管道中增加一个步骤,导致构建中断,否则就会通过,人们会感到沮丧。你必须和他们合作才能回到绿色。这没问题,但要做好准备。任何有一段时间没有打补丁的系统都将需要明显更多的时间来清理,因此在打补丁的最初阶段,请确保与团队和管理层进行协调。将事情部署到服务组,并准备在最初几轮修补发生时,为特定服务提供临时例外或短期禁用。
这一阶段的核心原则是嵌入开发过程的快速反馈循环有助于团队使其成为持续活动的一部分,而不是需要大块的单独跟踪工作。这使得团队更容易遵守。
自动化生产扫描
尽管 CI/CD 集成改变了游戏规则,但它本身不足以进行漏洞管理。它在捕捉由新部署引起的漏洞方面做得很好,但漏洞的挑战之一是它们总是在现有软件中被发现。今天可能会出现一个漏洞,它会影响昨天通过所有测试并投入生产的代码。CI/CD 只是拼图的一半;生产环境扫描是另一半。
换句话说,为了与团队沟通的效率,与 CI/CD 的集成是无可匹敌的。但是为了全面了解您的漏洞,需要进行产品扫描。
回到我们去过的电子表格…
…但不会太久。电子表格对于获得数据的概览非常有用,但是如果您想要开始生成票证并报告您的漏洞管理进展情况,您将需要比电子表格所能容纳的更多的分析。因此,我们构建了一个集成管道,为安全团队自动化了最大的手工工作。这意味着从生产漏洞扫描器中取出数据,并将其放入票证中。正如我之前强调的,让安全团队使用他们已经在日常使用的工具与工程团队会面是一个非常好的主意,所以让我们的程序将数据转化为票证是至关重要的。
这不仅仅是一个简单的连接器。从漏洞扫描器获取数据并将其转换为票证的过程涉及复杂的细节,需要我们使用真正的编程语言。我选择在 Clojure 中实现这种自动化,因为这是 CircleCI 的主要开发语言,在做技术决策时,考虑维护是很重要的。这必然包括考虑让公司里的其他人来维护工具。
乍一看,这种集成听起来非常简单:从 prod 漏洞扫描器中取出数据,对其进行转换,并制作标签。著名的遗言。
这种集成需要牢记许多挑战:
我们需要更新现有的票证,这样开放的票证就不会重复。我们在吉拉添加了一个 vuln-mgmt-id 来跟踪图像/门票身份映射
随着时间的推移,源 API 和目标 API 都发生了显著的变化。为了解决这个问题,我们围绕集成的 API 构建了抽象层,包括吉拉和扫描工具。
该服务必须将所有不同发行版、库和工具的奇怪数据标准化,使之保持一致。从“适度”到“中等”(容易),再到每个供应商都有不同的“固定版本”(更难)。
为了解决这一问题,我们构建了一个数据标准化层,该层将严重性标准化,在子包中删除重复的 CVE(常见漏洞和暴露),并解析许多不同的字符串格式以获得修复版本。我们还标准化了包信息,以便向团队提供明确的要求,告诉他们应该在票证细节中修补哪个版本。
在吉拉工程项目和团队变更时,如何将船票分配到正确的目的地。我们创建了一个灵活的团队分配配置,包括正则表达式和部分匹配。团队分配中的另一个关键学习是,如果配置匹配多个团队或零个团队,则抛出一个错误。这将通知安全团队是否需要任何额外的配置。
这需要相当多的工作,但却产生了一个简单的命令行应用程序,它可以读取最新的信息,生成详细的票证,并在几分钟内将它们分配给团队。
此阶段的关键原则是投资自动化,消除安全团队的重复和易错工作。像灵活的团队配置这样的事情每周都节省时间,因为团队分配或未知容器的小变化经常发生。
生产报告
关于安全工作,要记住的一件关键事情是,仅仅做正确的事情是不够的;你必须能够表明你在做正确的事情。报告的目标是创建一个涵盖所有人(高管、团队经理、审计员)需求的单一报告。这不仅节省了工作,而且有助于确保每个人对事物的状态有相同的理解。
由于 Docker 的漏洞管理不同于传统的修补,我们必须与我们的审计员合作,以便他们能够了解我们是如何分配工作的,并利用我们生成的报告。传统上,系统管理员团队是打补丁的人,这是我们的审计员习惯看到的。这需要一些工作来解释,在我们的例子中,整个组织的每个工程团队都要打补丁。经过一番反复之后,我们在报告中添加了一些额外的细节,并能够设计出一种满足 FedRAMP 审计员和内部利益相关者需求的报告格式。
此阶段的主要原则是调查并找出一份令所有相关方满意的报告,然后自动生成该报告。
优化修补
与各个团队合作,优化他们的修补方式。确保这是合作而不是命令。目标是帮助他们将补丁安装到现有工作流中,而不是创建新的工作流。请记住,工程团队更熟悉他们的流程,并且会有一些关于如何以安全团队可能没有想到的方式进行优化的好主意。
这里最有成效的三种技术是自动化集成测试、共享基础映像和软版本规范。
- 自动化集成测试,一般来说应该是 CI 管道的一部分,允许更快更有信心地应用补丁。因为补丁自动运行完整的集成测试套件来检测由补丁引起的问题,所以这允许需要更少人力的补丁查看方法。
- 共享的基本 Docker 映像允许具有相似基础架构和软件需求的服务基于一个公共映像。常见更新的收集在一个映像中完成,然后推广到所有特定的服务。这让大多数开发团队可以简单地将最新的共享作为任何补丁的第一步。
- 通过简单地指定包的主要版本或主要+次要版本,并让包管理器作为预定 Docker 映像构建的一部分自动更新到最新版本,就可以完成软版本规范。如果计划的构建每周运行一次,并且消除了许多对持续修补的人工干预。这种自动化版本碰撞存在一些操作风险,因此如果开始这种级别的自动化,进行彻底的集成测试并首先在不太关键的服务上进行测试是非常重要的。
这一阶段的核心原则是使贴片更容易。对安全团队来说,对漏洞进行深入分析和优先排序既昂贵又耗时。错误地将高严重性漏洞标记为在环境中不适用也有很大的风险。如果补丁流程简单明了,团队将简单地应用补丁并使一切变得更容易。
漏洞管理提示
(或者,如何与审计员、Docker 和 CI/CD 系统合作)
- 使用工程团队已有的工具和流程与他们合作。
- 一开始不要太教条。
- 在您现有的 CI/CD 中构建补丁。
- 投资漏洞管理的自动化。
- 创建包含所有利益相关者所需信息的单一报告。
- 使应用补丁简单明了。
结束语
在推出漏洞管理时,很容易陷入早期关注并进入救火模式。请记住,这不仅仅是一轮修补、一个关键漏洞或一个团队或映像。这是一种一致的可重复自动化,可持续提高安全性,同时最大限度地减少对工程和安全团队工作流程的影响。
如何找到产品与市场的契合度
原文:https://circleci.com/blog/how-to-find-product-market-fit-with-the-right-startup-tools/
你的首要任务:找到适合市场的产品
在任何创业公司中,找到最适合市场的产品都要从客户那里获得反馈。这是你在任何业务的萌芽阶段所能做的最重要的事情。现代软件工具使得你的想法在第一天就呈现在用户面前成为可能——但情况并非总是如此。
20 多年来一直在寻找适合市场的产品
1998 年,我有了第一份软件工作。那时情况很不一样。我们的第一个服务器就住在我的桌子下面。当我们筹集到种子资金时,我飞到弗吉尼亚州的赫恩登,亲自建造我们的数据中心。我带着装满磁盘驱动器的手提箱乘飞机。1998 年,你就是这样把软件放到互联网上的。
今天,你很幸运能够在 AWS、Heroku 和无服务器时代创业——这意味着你拥有我在 1998 年没有的优势。事实上,这些选项在 99.99%的商业历史中都不存在。
现代云部署平台让您能够比以往任何时候都更快地将您的想法传递到用户手中。有了这样的工具,当用户与你的产品交互时,你可以完全专注于产品的开发,这样你就可以尽快地从这些用户那里学习。
考虑到这一点,我想提醒你注意一些过时的创业实践。
恐惧不是一个有用的启动工具:不要在秘密模式下开发
秘密模式是初创公司秘密开发产品的阶段,他们不会谈论或向任何人展示产品,以免别人窃取他们的想法。
在我解释为什么这是一个坏主意之前,让我首先说,围绕着构建隐形模式的恐惧通常是没有根据的。人们不会坐以待毙,只是等待一个可以窃取并创造的好主意。如果有人有时间和精力来窃取你的想法,他们可能已经有了自己的想法,并且正在为之努力。
但更重要的是,对于你目前正在做的任何事情,现在至少有三个其他团队在某个地方,也在研究这个想法。
快速开发=更快发现产品与市场的契合度
你能做的最好的事情不是秘密地工作,而是建立它,并尽快让它出现在客户面前。保守秘密会延长你建造它的时间的想法是错误的——你只是增加了有人在市场上击败你的机会。
不要秘密建造;在公共场合建造。不要花时间让它变得完美;做一些不完美的东西,并尽快得到反馈。
隐身模式的对立面是什么?登录页面。登陆页面是可行概念的第一个、最小的测试。我可以在早餐前提出 5 个商业想法,看看哪一个在午餐前最吸引人。我没有浪费任何时间,我得到了关于我的市场的有价值的信号。我花了一个小时,没有写任何代码,这已经是一个比秘密模式更好的主意了。
对于早期创业公司来说,找到适合市场的产品是唯一重要的事情。秘密地制造你的产品并不是找到适合市场的产品。如果你隐瞒了什么,你就没有从中吸取教训。
商业计划考虑因素
在你说“Rob Zuber 告诉我不要有计划”之前,我认为有计划是非常重要的——只要能用一句话清楚地表达这个计划。不要做不必要的计划,这意味着:计划你的下一步,建立它,并获得反馈。然后修改计划。重复一遍。
缺少那种大规模的、预先的、三环活页夹式的计划通常被解释为缺少计划。但实际上,这意味着我正计划处于一个最佳位置来抓住一个机会,随着我工作的进行,我将不断完善这个计划。
犯错实际上是一个关键的启动工具(不是开玩笑)
不写商业计划的真正原因是,不管你的商业计划有多聪明,你都是错的。你在生意上做错了一些事情。回想一下其他三个团队提出的相同想法。他们也错了。但你们都不明白自己错在哪里。在这一点上,你唯一的策略是尽可能快地犯错(最好比其他团队更快),这样你就能发现什么是正确的,并开始构建正确的东西。
你唯一的策略是尽可能快地犯错误,这样你就能发现什么是对的,并开始做正确的事情。
这可能不会让你感到惊讶,但这个建议并不仅仅针对早期创业公司。在每个阶段,保持构建、执行和获得反馈的循环。只有在这个反馈循环中,你才会知道自己错在哪里,并开始变得更加正确。
了解有关寻找产品市场契合度的更多信息
放下你的商业计划。找到你的想法的最简单的近似,这将会给你任何类型的信号。用一个下午的时间把它做好,然后把它送给别人,看看他们是否在乎。尽一切努力找出答案——不应该花 18 个月和一份 90 页的文件。
想更深入地了解如何找到最适合你的创业公司的产品市场(以及我的 14 条技术领导力规则)?下载我最新的电子书,选择一个你不会后悔的技术堆栈:快速成长的初创公司技术领导力指南。
如何在 CircleCI 找到工作
来自出版商的说明:您已经找到了我们的一些旧内容,这些内容可能已经过时和/或不正确。尝试在我们的文档或博客中搜索最新信息。
在与我们的开发者代言人 Alek Sharma 进行了一次振奋人心的谈话后,我决定写一份同样振奋人心的号召书来描述我们的招聘流程。
那么,你是一名软件工程师。你擅长从抽象概念中创造价值,在你的脑海中编织各种功能。你知道真正的问题包括真正的工作——成功和失败的有力结合,彻底混合,并提供一把小雨伞。
你最想做的就是能够解决这些真正的问题,伸张正义,不受惩罚地攀登达蒙。但是你的抱负被面试过程的铁蹄碾碎了:他们没有接受你的挑战,而是让你经历了一次。在一连串的电话屏幕中,你说你的台词:
“是的,我很好奇。”
“自我激励?我每天早上都从自己做起。”
“我是重构工厂。”(这张在 Alek 的 LinkedIn 个人资料上,请不要偷。)
当你到达现场时,你被带进一个房间,在那里你坐了 13 分钟,啜饮一罐不冷不热的酸橙汁。一个严肃的工程师走了进来,介绍了自己,聊了几句。然而,最终:
“反转一个链表,在适当的位置……”你的审问者吟诵道。
然后他们用食指指着冰冷的白板。它甚至也不会是白色的——你会看到世博会标志的淡色条纹,是你不幸的前任留下的可耻痕迹。
你额头上冒出汗珠。如果你打开了破解编码面试 …
从这场噩梦中醒来!
…因为你在 CircleCI,而且我们不做白板面试-手写代码不会编译或执行。
白板面试是为那些不知道自己想要什么的公司准备的。他们会让你写到手抽筋,但他们只会知道你在墙上的伪代码写得有多好。
这是我们在 CircleCI 使用白板的方式:
头脑风暴!图表!思维导图!所有这些都是使用白板的好东西。在任何地方你都不会看到某个可怜的灵魂的采访腐烂的遗迹。
我们不在乎你有多擅长解决任意的智力谜题,因为这不是我们在这里做的。
我们相信务实的工程师
我们做的是编写和发布软件。我们喜欢认为我们在做这件事上是务实的,这意味着我们更喜欢“装运”而不是“完美”。这就是为什么我们用 Clojure,一种设计用来完成事情的语言。我们不雇佣纯粹主义者或教授——我们没有时间做这些。
但是,这并不意味着我们马虎:不,我们通过编写测试和持续集成我们的代码来快速行动并避免破坏事情。
所以我们想听听你们是如何做这些事情的。我们会让你处理我们实际代码中的实际 bug,因为我们想让你知道你将进入什么状态。
我们也相信人类工程师
优秀的工程师知道如何沟通。
复杂的系统失去了它们的神秘性,争论变成了妥协,我们都变得更加快乐。这就是为什么我们的面试过程涉及这么多的谈话:我们想要喜欢你,我们想要你喜欢我们。当我们不能相处的时候,写出好的软件会困难很多。
沟通更为重要,因为我们的团队遍布世界各地:是的,我们在旧金山有工程师,但我们在波士顿、多伦多、都柏林、柏林、东京、悉尼等地也有工程师。
这就是为什么你会和我们一起研究一个真正的特性或缺陷。因为这就是你在工作中要做的事情;当然,不是每天——人们需要自己的私人空间——但是协作是在这里工作的重要组成部分。阅读 CircleCI 在的实习经历以及他对 CircleCI 如何开展合作的看法。
因此,停止白板演示,现在就申请。
如何处理 Java OOM 错误
来自出版商的说明:您已经找到了我们的一些旧内容,这些内容可能已经过时和/或不正确。尝试在我们的文档或博客中搜索最新信息。
试图在一个 CI 环境中控制 Java 的内存使用可能是一种黑暗的艺术。
由于 Java/Android 项目有丰富的构建框架可用——Java、Gradle、Maven(更不用说 Kotlin 和它自己的工具生态系统了)——很难控制内存的去向以及如何限制内存。您可以设置各种不同的环境变量来管理内存使用,它们都具有相似的名称和语法。这些变量以一种最初可能没有多大意义的方式相互作用。默认情况下,CircleCI 上的项目构建在具有 4GB RAM 的虚拟环境中。这个 RAM 由项目中运行的所有进程共享:数据库、测试、各种工具/框架,以及贪婪的 Java 虚拟机(JVM)。
在没有任何内存限制的情况下,众所周知,Java 虚拟机会以大块的形式预先分配大量内存,这有时会导致您在 CircleCI 和其他 CI 平台上看到的内存不足(OOM)错误。此外,CircleCI 运行在具有大量 RAM 的虚拟机上,使用 cgroups 为每个单独的构建分配一块馅饼。当 JVM 询问它的主机它可以使用多少 RAM 时,它看到的是整个饼图,而不是分配给它的构建的特定 cgroup 的 RAM。
最后,当 OOM 错误确实出现时,它们通常只不过是一个exit code 137
错误,隐藏在一个长长的构建日志的底部。是什么导致了这些类型的错误,减轻这些错误的最好方法是什么?让我们看看设置 JVM 内存限制的不同方法。您可以参考这个方便的图表来查看这些不同的环境变量是如何相互作用的。
数字表示优先顺序,即 0 优先,3 优先。
| Java 环境变量 | Java 语言(一种计算机语言,尤用于创建网站) | 格拉德勒 | 专家 | 科特林 | 莱因 |
| _ JAVA _ 选项 | 0 | 0 | 0 | 0 | 0 |
| JAVA _ 工具 _ 选项 | 2 | 3 | 2 | 2 | 2 |
| JAVA_OPTS | 不 | 2 | 不 | 一 | 不 |
| JVM_OPTS | * | 不 | 不 | 不 | * |
| LEIN_JVM_OPTS | 不 | 不 | 不 | 不 | 一 |
| 梯度光学 | 不 | 一 | 不 | 不 | 不 |
| MAVEN_OPTS | 不 | 不 | 一 | 不 | 不 |
| CLI 参数 | 一 | 不 | 不 | 不 | 不 |
****** lein 会将 JVM_OPTS 的值传递给它所衍生的 Java 进程;然而,这个 env 变量不影响 lein 本身(为此,使用 LEIN_JVM_OPTS),也不会影响任何直接启动的单独 Java 进程(为此,使用 _JAVA_OPTIONS 或 JAVA_TOOL_OPTIONS)*
_JAVA_OPTIONS
这是最强大的 JAVA 环境变量。它由 JVM 直接读取,并覆盖任何其他 Java 环境变量,以及您在命令行上传递的任何参数(例如,java -Xmx512m -Xms64m)。出于这个原因,通常不推荐使用 _ JAVA _ OPTIONS——更集中的方法通常也能很好地完成工作。
同样值得注意的是_JAVA_OPTIONS
是特定于 Oracle 的,所以它并不适用于所有情况。例如,对于 IBM 的 Java 工具,您需要使用IBM_JAVA_OPTIONS
。
JAVA _ TOOL _ OPTIONS
这个是设置 JAVA 内存限制的安全选择。所有 Java 虚拟机都可以读取它,并且很容易被覆盖,要么使用命令行参数,要么使用更具体的环境变量,这取决于您的构建工具。而且比_JAVA_OPTIONS
更擅长处理报价。
JAVA_OPTS
有些令人误解的是,JAVA_OPTS 实际上并不被 JVM 读取,而是被各种常见的基于 JAVA 的工具/语言用来将内存限制传递给 JVM。
JVM_OPTS
JVM_OPTS 是 Clojure 特有的:lein 用它向 JVM 传递内存限制。然而,它实际上并不影响 lein 自己的可用内存——为此,您将需要 LEIN_JVM_OPTIONS。再者,它不是 Java 原生识别的,所以不能用它直接把内存限制传递给 Java;为此,请参见 JAVA_OPTIONS 或 JAVA_TOOL_OPTIONS。
GRADLE_OPTS
可以预见,这个变量用于为 GRADLE 项目设置内存限制。它优先于任何用于设置 JVM 内存限制的通用 env 变量——除了 JAVA_OPTIONS。
MAVEN_OPTS
您可以使用 MAVEN_OPTS 为用 Apache Maven 构建的项目设置 Java 内存限制。像 GRADLE_OPTS 一样,这将覆盖 JAVA_TOOL_OPTIONS,但不会覆盖 JAVA_OPTIONS。
调试 OOM 错误
当谈到调试不透明的 OOM 错误时,您最好的选择是寻找那个exit code 137
。让我们以 Gradle builds 为例。当构建在 Docker 上使用太多内存并被 Linux OOM killer 终止时,Gradle 会产生令人困惑的错误消息。
Gradle 通过为构建过程启动子过程来工作。当一个构建使用太多内存时,通常是子进程的错误,而不是父进程的错误。子进程被终止,父进程被告知两个进程都以代码 137 退出。错误消息可能会说“意外的进程退出,代码为 137”,或者您可能会看到“Gradle build daemon 意外消失”(退出代码 1),或者甚至只是”。/gradlew 意外死亡”,根本没有任何退出代码。这些错误消息都没有提到“内存”、“cgroup”、“docker”或“oom killer”这样的词,所以诊断这个问题真的很难。
不过,现在已经有帮助了:Java 有了一个新的(有点)能力,可以读取你构建的 Docker 容器的 cgroup 内存限制,而不是(错误地)读取整个机器的总内存。这些新选项应该可以让 JVM 更容易地使用机器上的“大部分”内存,而不会溢出。
总之,最好确保您的-Xmxn
最大大小足够让您的 Java/Gradle/Maven 应用程序构建、测试和部署,但又足够小,让其他进程充分共享您的 CircleCI 构建容器中的剩余内存!
当然,如果有必要的话,我们可以随时提高你项目的 RAM 。
延伸阅读:
如何帮助你的团队在变革中茁壮成长
原文:https://circleci.com/blog/how-to-help-your-team-thrive-in-times-of-change/
2020 年 3 月 1 日,是一个星期天。我正准备去旧金山出差。在去柏林机场之前,我检查了我的手机。我老板发来一条短信:
嘿,莉娜,尝试所有频道。不要飞。
那天我没有飞,从那以后也没有飞。
两天后,按照计划,我从 CircleCI 的临时产品工程副总裁变成了永久副总裁。与此同时,欧洲进入封锁状态,然后世界进入封锁状态。我们所知的生活瞬间改变了。
突然间,我的新角色有了更大的意义。我必须想出如何有效地完成我们的业务目标,并在难以置信的不确定性中支持我的团队。
过去的一年很艰难,但它也教会了我很多如何领导变革并帮助我的团队茁壮成长。
投资你的团队
作为领导者,我们需要成长并投资于我们周围的人,无论是在正常时期,还是在不确定时期。这是我们最大的任务之一,因为这意味着建立一个能够学习、适应、发展和适应变化的团队。
这项工作的一个主要部分是培养领导者:我们需要确定有抱负的领导者——具有高潜力的团队成员——并为他们提供成长环境,为他们分配成长机会,并设定延伸任务和目标。在我的职业生涯中,我所见过的成功的领导者是那些在职位上升时授权并带领他人的人。让没有简单答案或清晰路径的人参与讨论,这样他们可以学习如何处理歧义。
我做到这一点的方法之一是,经常与我的直接下属分享战略会议的笔记,让他们了解这类讨论的背景和内容。另一种方法是定期将战略问题委派给他们,一起解决问题。
像人一样支持你的员工
在疫情,保持良好的人际关系并了解同事的需求甚至更为重要,因为生活往往会频繁变化。但是这些联系必须是真实的。
回到 11 月,当美国大选的结果尚不明朗时,我团队中的许多人都感到焦虑。像我这样的团队规模较大,目前有 4 个直接下属和 10 个越级下属,因此没有“一刀切”的方法——每个人的应对方式不同,每个人的需求也不同。
我的方法是分享一些关于如何与你的经理、同事和直接下属谈论正在发生的事情的技巧。但我也确保分享一些可爱的动物视频给那些需要分散注意力的人。重要的是提供一系列选项来帮助你的团队应对不确定性,让他们选择最适合自己的方案。
庆祝大大小小的胜利
在一个快节奏的环境中,很容易掩盖胜利,但承认他们是一个团队,可以确保每个人都感到被重视。庆祝,即使是以一种小的方式,向为整个团队出现的人表达你的感激之情。
表达感激的方式有很多。当我的队友做得很好,或者我看到他们在职业发展中取得进步时,我喜欢给他们发短信。我偶尔会公开表扬我的直接下属,但这种情况很少见。我知道其中涉及的权力动态,有些人觉得公开表扬让人不舒服。同样,每个人都是不同的,根据每个人的需求调整你的领导风格是至关重要的。
坚持你的价值观
作为经理,我们经常被置于新的环境中,在危机时刻,我们通常是人们第一个求助的人。在我的职业生涯中,我多次问自己想成为什么样的领导者。在与我自己的经理讨论应该如何对待员工、公司应该如何运营或者我们应该如何践行我们的公司价值观时,我提到了这一点。
我决定如何领导的一个方法是,在每个工作日开始时坐下来,花 10 到 15 分钟思考战略主题和问题,以及它们与 CircleCI 当前工作的关系。我还会定期与我的员工联系,了解我们团队的发展方向,以及我们与共同期望的差距。这可能看起来真的很简单很小,但是非常有效。
作为领导者,我们需要确保当下得到有效管理。同时,我们必须预测下周、下个月和明年将会发生什么,让我们的团队为未来的变化做好准备。但是你不能忽视你自己和你在工作中的价值。作为一名领导者,你能做的最好的事情之一,尤其是在不确定的时期,就是用你的价值观来引导你的团队度过那些充满挑战的时期。
这篇文章最初发表在我们是科技女性T3
如何在工作中给出快速有效的反馈
原文:https://circleci.com/blog/how-to-incorporate-fast-positive-feedback-into-your-team-s-work/
健康的反馈对于创造一种团队成员感到安全、相互联系并有动力做好工作的文化至关重要。根据我的经验,快速反馈(Sfeedback)是在工作中促进健康反馈文化的一种简单而有效的方式。
反馈就像快速约会一样,给予和接受积极的反馈。团队成员相互配对,在快速(10 分钟)远程会议中给予和接受反馈。确保一切顺利运行需要一些准备,但好处是值得的。Sfeedback 可以帮助您的团队更加自如地提供和接受反馈,并鼓励他们在职业发展过程中将其融入到工作中。
需要注意的是,尽管 Sfeedback 对于给予和接受积极的反馈非常有用,但它并不是建设性反馈的最佳环境。查看这篇文章,了解更多关于促进建设性反馈会议的最佳方式。
如何准备远程反馈会话?
根据我的经验,Sfeedback 可以很好地与五人以上的人合作,因此每一对可以会面 10 分钟,整个会议只需要一个小时。每个人都应该提前有足够的时间为所有参与者准备反馈,因为在整个会议过程中,他们将与每个人单独会面。
当我准备课程时,我会尽量让过程简单。直到最近,我从来没有虚拟地这样做过,所以我花了更多的精力来准备这个会议,以确保它顺利进行。
1)第一步是召开一次会议,向您的团队介绍反馈。告诉他们在课程中会遇到什么,他们需要如何准备,重要的是,你为什么要做这个练习。让他们知道这对团队有什么好处。
2)在发送日历邀请前至少一周,设置反馈会议的日期。创建邀请,并统计有多少人可以加入,这样你就可以开始配对。
3)将总对数相加,计算每对在每节课中可以花费的时间。确保考虑过渡时间。
4)创建一个表示会话和对的 Sfeedback 表。
为了减少混乱(对我自己来说),我创建了一个类似上面的表格,这样我就可以在心里模拟这个会话。当你安排两人一组时,尽量让一个人呆在同一个房间里,这样走动的人就少了。我也给了人们一分钟的缓冲时间来加入下一个电话。
5)为活动创建缩放链接。确保缩放设置允许人们在没有主持人的情况下加入。这一步可以是可选的,但我发现它为参与者节省了麻烦和时间。
6)创建个人日程表,通过 Slack 或电子邮件与他们分享。也给他们发一份如何准备课程的提纲(见下文)。
7)在课程结束时,将所有参与者召集到同一个缩放室,询问他们对该练习的总体感受。建议他们安排 1 对 1,跟进他们没有完成的任何重要反馈。
你如何参与反馈会议?
了解如何参与反馈会议与组织反馈会议一样重要!在会议之前,将这些说明发给你的团队,让他们知道如何准备。
1)确保为你的合作伙伴准备好周到的反馈,因为他们也会为你做同样的事情。例如,“你真棒”,虽然经常是真的,但不是有用的反馈。多想想为什么你觉得你的伴侣很棒,并与他们分享。表现出你关心你的队友的成长,你喜欢和他们一起工作,这很重要。这是一个鼓励他人并提醒他们对团队有多重要的机会。
2)尽量尊重时间窗口。快速提供您准备好的反馈,并进入下一个电话是乐趣的一部分。如果您没有检查您准备的所有反馈,请安排单独的一对一总结。
3)请将建设性的反馈留给下一次一对一的会议。阅读这篇文章,它涵盖了促进和参与建设性反馈会议的一些最佳实践。
4)最后,享受课程!这项活动的团队凝聚力和反馈一样有价值。
在反馈会话期间,您应该避免什么?
同样,Sfeedback 不是用来分享建设性反馈的。每个反馈会议大约 5 到 10 分钟,建设性的反馈需要更多的时间,以避免误解并确保有效的反馈。利用这个环节向你的队友介绍积极的反馈更合适。
自从在 CircleCI 向我的工程团队介绍 Sfeedback 以来,我已经看到了许多好处,但我认为最令人兴奋的是,我的初级团队成员现在更愿意提供和接收反馈。他们中的一些人甚至特别要求定期得到建设性的反馈。我的团队非常喜欢反馈会议,所以他们要求把它变成一种常规做法。
DevOps 成熟度| CircleCI
原文:https://circleci.com/blog/how-to-lead-your-team-to-devops-maturity/
许多团队现在正在转向 DevOps,这是有充分理由的:使用 DevOps 实践有助于团队更好地响应市场变化。他们可以更快、更安全地部署代码,更不用担心中断生产。
但是切换到 DevOps 并不是一个非此即彼的命题。DevOps 是一种将运营知识带入开发的思维模式,是的,但是它也伴随着一整套过程、方法和使用工具的方式,使它与众不同。成熟的 DevOps 组织的领导者只是以不同的方式思考工程。
坏消息是,你不可能某天早上醒来就决定“做”DevOps。但好消息是,迈向 DevOps 是一个永无止境的旅程!这意味着任何团队都可以从现在开始成为一个更成熟的开发运维组织。
在我们最新的电子书中,CircleCI 首席技术官兼资深工程领导者 Rob Zuber 向我们展示了他职业生涯中在最高效的工程组织中应用的 DevOps 原则。他分析了一个不断改进的 DevOps 心态是什么样子的:一个苦苦挣扎的团队应该把精力集中在哪里?一个快速发展的团队接下来应该从哪里着手改进?如何在不损失速度的情况下开始测量管道中的所有东西?
阅读电子书,学习如何让你的团队更上一层楼。
下载带领你的团队走向 DevOps 成熟。
如何用 CircleCI 做开源贡献
或者,作为一名支持工程师,我是如何编写我们迄今为止最常用的 orb 的(你也可以这样做)
开源经验
如果你是一个新的开发者,我在这里鼓励你考虑写一个 orb。orb 是在你的简历中添加一些开源经验的好方法,同时展示了软件工程角色寻找的大部分技能。
- 开源开发经验
- 具有持续集成和持续部署的经验
- Git 和 Bash 体验
用一个简单的 orb 实现所有这些要点真的很容易,即使它只是将消息发布到一个 Slack 通道。事实上,这就是我所做的,也是我将在这篇博文中讨论的。
我是谁?
嘿,我是凯尔,CircleCI 的支持工程师。如果您以前联系过支持部门,我们可能已经见过面了。我也尝试在邮件系统之外提供支持,写支持中心的文章,创作视频,现在还有 Orbs!我想我们也可以添加博客帖子。
我有机会与我们的许多用户交谈,并观察你们所有人提出的简化开发的创造性解决方案,我试图利用这些观察,向你们提出可能的最佳解决方案,或者有时我们应该对我们的团队做出的改变。
一些关于球体的背景
几个月前,我们从产品团队那里得知,我们将很快发布" Orbs ",一个 CircleCI 配置文件的包管理器。例如,您可以使用 orbs 轻松配置 AWS S3 上传,而无需担心安装 AWS CLI 或创建 AWS 配置文件。有了这样一个 orb,你根本不需要担心 AWS 这边,也不应该有!你的重点是你的项目;你希望 S3 上传不需要维护就能正常工作。对于球体来说,几乎所有东西都是如此。
比如上传到 S3,就是这么简单:
导入球体
orbs:
aws-s3: circleci/aws-s3@volatile
然后,您可以随时在任何作业中分步运行同步命令
- aws-s3/sync:
from: bucket
to: 's3://my-s3-bucket-name/prefix'
overwrite: true
就是这样!所有的 Orb 都是开源的,所以你可以在我们新的 Orb 注册页面上看到它是如何制作的,并阅读如何使用它的文档:https://circleci.com/developer/orbs/orb/circleci/aws-s3
使用 orbs,任何人都可以非常容易地快速实现大量的集成、工具、实用程序、特性或任何您能想到的东西,并共享它们。
作为一名支持工程师,这可能会也可能不会让我超级开心!没有什么比拥有一个标准化的解决方案来呈现给每个人更好的了,而且这个解决方案很容易作为一个单一的包来维护。
第一步:解决一个简单的问题
在 orb 向公众推出之前,产品团队的任务是为发行版开发一组初始的 orb,他们邀请其他团队参与到这个过程中来,并贡献 orb。因为我是回答你关于球体问题的人之一,所以我借此机会创造了一个我认为对很多人有用的球体。
由于我直接与用户交谈,我知道你们都希望对 Slack 通知有更多的控制:何时发送,发送什么,谁被警告,甚至可能是消息的颜色。所以我决定创造一个球体来做到这一点。创建 orb 的过程非常简单,这向我展示了做一个很多人都会使用和改进的开源贡献是多么容易。事实上,我写的 Slack orb 现在是我们迄今为止使用最多的 orb。
“当我开始的时候,我不知道这个项目会发展到什么程度,会被社区所塑造。”
看着社区成长
自从我写了 Slack orb 之后,我收到了很多像您这样的用户的请求,他们希望在自己的项目中使用和改进 Slack orb。最初本质上是一个 CURL 请求的包装器,现在已经发展成为 CI 和 Slack 之间的一个健壮的、由人对人的接口,具有一些高级功能,比如在部署等待您的批准时能够接收丰富的通知。当我开始的时候,我不知道这个项目会发展到什么程度,会被社区所塑造。
看着松弛的球体
让我们来看看 Slack orb,它是做什么的,以及它是如何做到的。您可以将这里的原则应用于任何工具或 CLI。
如果你想跟随源代码或者只是自己检查一下 Slack orb,你可以访问 Orb 注册表。
它的作用
虽然 orb 自创建以来已经有所发展,但最初的 Slack orb 只有两个命令,“notify”和“status”:
让我们来看看在notify
指挥下的。
jobs:
alertme:
docker:
- image: circleci/node
steps:
- slack/notify:
message: "This is a custom message notification"
#Enter your own message
mentions: "USERID1,USERID2"
#Enter the Slack IDs of any users who should be alerted to this message.
color: "#42e2f4"
#Assign custom colors for each notification
webhook: "webhook"
#Enter a specific webhook here or the default will use $SLACK_WEBHOOK
notify
允许您在任何工作中轻松创建自定义时差通知。这允许您以多种方式自由发送通知。
首先,您可以设置几个参数,比如消息文本、要@提及的任何用户,甚至是显示消息的盒子的颜色。
您还拥有基于作业有条件运行通知的固有优势,这意味着您只需将notify
命令添加到您的部署作业中,并选择向团队成员发出警报。
最令人兴奋的是,球体的灵活性意味着你可能会想出这个球体的创造性用途,这是我从未考虑过的。
如果你想了解更多关于 Slack orb 的信息,可以看看 orb 注册表上的页面。想贡献和改善懈怠宝珠?是开源的!给我们发一份公关,我们会看看。
我是如何建造我的球体的(当然你也可以)
这个项目开始于我的个人 Github,后来当它准备好发布时,被转移到了 CircleCI 官方组织。如果您正在寻找任何灵感或证据来证明没有人是完美的(甚至是接近完美的),您可以查看 git 提交历史来查看与实现这一点相关的所有试验和错误。老实说,我感觉至少有 100 个提交在引号、双引号和转义字符中挣扎。
你可以在 CircleCI 的新主页上通过更新和拉取请求看到它今天的样子:https://github.com/CircleCI-Public/slack-orb
现在轮到你了:为什么要创作一个球体?
为什么要为您的开源项目选择 orb?因为它很容易上手,并且提供了很多重要开发技能的经验,而且由于它是开源的,CircleCI 将免费构建它!
加入开源社区:我们最近开始收到关于 Slack orb repo 的第一个“问题”报告,仅仅是知道开发人员正在使用您的代码就感觉棒极了。
自从创建 Slack orb 以来,我们已经收到了几个 pull 请求,通过发布补丁或新功能对几个问题做出了响应,并使用工作流和 CLI 构建了一个更强大的开发管道来实现自动部署
现实世界技能:创建一个 orb 或改进一个现有的 orb 是一种非常简单的方式,既能参与开源社区,又能获得雇主所寻求的现实世界经验。
orb 本质上利用了 Git 版本控制、CI/CD 和 shell 脚本,以及在这个过程中可能与之交互的任何其他 CLI 或工具。
使用CURL
编写一些向 Slack 通道发布消息的东西,包含了成为专业开发人员所需的几乎所有经验。如果你想进入这个领域,我想不出比这更好的开始方式了。
在我的下一篇文章中,我将分享我的最佳技巧和创建球体时需要考虑的事情。准备好了吗?探索宝珠。
如何衡量 DevOps 的成功
原文:https://circleci.com/blog/how-to-measure-devops-success-4-key-metrics/
用最新的软件交付数据衡量开发运维的成功
为了衡量 DevOps 的成功,您需要行业基准来量化关键的软件交付成功度量。今年,我们基于来自我们平台上 44,000 多家组织的 5,500 万个数据点,为实践 CI/CD 的团队设定了首个基准。从数量上看,高绩效的工程团队是什么样的?
作为世界上最大的独立 CI 提供商,我们有一个独特的机会来定量调查软件交付的情况:在数万个团队中,逐个提交。有了真实的交付数据,我们可以看到团队是如何在实践中构建和部署软件的。
你的团队的交付能力是一种竞争优势。你应该瞄准哪些数字来保持领先?
下载 2020 年软件交付状态:工程团队的数据支持基准了解最成功的团队如何更好更快地构建。
衡量您团队的 4 个关键基准
我们关于工程团队绩效的综合数据为高绩效软件团队确定了以下四个基准:
- 吞吐量:大部分时间或所有时间,工作流运行的数量不如处于部署就绪状态重要
- 持续时间:团队希望工作流持续时间在五到十分钟的范围内
- 平均恢复时间:团队应该致力于通过在一小时内修复或恢复,从任何失败的运行中恢复
- 成功率:90%以上的成功率应该是你默认应用分支的标准
衡量这些成功指标的目的是什么?让我们更深入地了解这些指标的含义,以及为什么它们对您的团队如此重要。
关键指标:持续时间
持续时间定义为工作流运行所需的时间长度。这是列表中最重要的指标,因为创建快速反馈周期(包括吞吐量和平均恢复时间)取决于持续时间。换句话说,你不能推动一个修复,即使是一个非常需要的修复,比你的工作流运行的时间还要快。持续时间也代表了开发人员获得有意义信号的速度(“我的工作流运行是通过还是失败?”).较短的持续时间需要优化的工作流程。
并非所有工作流都产生相同的结束状态。例如,一些工作流只运行特定的测试,这取决于应用程序代码库发生变化的部分。因此,持续时间不是部署到生产环境需要多长时间的明确度量。它只是衡量工作流结束需要多长时间。
CI 的终极目标是快速反馈。失败的构建信号需要尽快传递给开发人员;你不能修复你没有意识到的东西。但是意识并不是唯一的考虑因素。开发人员也需要来自他们失败构建的信息。获取正确的信息来自于为你的软件编写严格的测试。
这里需要强调的是,速度本身并不是目标。一个没有测试的工作流可以快速运行并返回绿色,这是一个对任何人都没有帮助的信号。团队需要能够尽可能快地对失败采取行动,并从失败中获得尽可能多的信息。没有质量测试套件,持续时间短的工作流不会为反馈周期贡献有价值的信息。目标是丰富的信息和短时间的结合。
关键指标:平均恢复时间
平均恢复时间被定义为失败和下一次成功之间的平均时间。这是列表中第二重要的指标:当你的团队收到一个失败的信号后,他们快速解决问题的能力是非常宝贵的。因为平均恢复时间随着更全面的测试覆盖而提高,所以这个指标可以代表应用程序测试的好坏。
失败的构建、有价值的信号、快速修复、通过构建:持续集成使得这些快速反馈循环成为可能。快速信号使团队能够尝试新事物,并对任何影响立即做出反应。同样,可靠的测试覆盖减少了对将破损代码引入生产代码库的担心,允许您挑战您的工程团队,使他们对他们开发的解决方案具有创造性和灵活性。
关键指标:吞吐量
吞吐量被定义为每天运行工作流的平均次数。当开发人员对共享存储库中的代码库进行更新时,会触发工作流。推送至您的版本控制系统(VCS)会触发包含您的工作流的 CI 渠道。
工作流运行的数量表明有多少离散的工作单元通过您的应用程序开发管道。吞吐量的一个组成部分反映了您提交的大小:您是推动许多小的更改还是较少的大的更改?合适的规模将取决于您的团队,但目标是让工作单元足够小,以便您可以快速轻松地调试,但又足够大,以便您可以部署有意义的更改。
我们建议监控吞吐率,而不是设定明确的目标。了解事情发生的频率很重要,吞吐量是提交频率的直接度量。吞吐量的波动可能发生在像 onboarding 这样的情况下,在这种情况下,两个开发人员可能一起完成相同的任务,结果导致提交更少。为您的组织建立基线度量可以为这种类型的影响做好准备,允许您通过这些可预测的事件来预测工程生产率。当您遇到不可预见的情况时,您的基线也能够帮助您确定未完成的工作量。
当一个经过良好测试的应用程序处于可以随时部署的状态时,这是因为每一个新的变化都经过了持续的验证。如果没有一个完全自动化的软件交付管道,一个团队会经常在不合适的时间(例如,星期五晚上)部署紧急事件和消防演习。
有了完全自动化的软件交付管道,更新交付给最终用户的频率(和时间)由您决定:即时热修复;开发时的功能升级;根据您的业务需求对日历进行大规模更改。目标不是每天特定的部署数量,而是通过你的管道持续验证你的代码库。
关键指标:成功率
成功率被定义为通过运行的次数除以一段时间内运行的总次数。依赖于主题分支开发(相对于默认分支开发)的 Git-flow 模型使团队能够保持他们的默认分支绿色。
需要注意的一件重要事情是,根据工作流是在默认分支还是主题分支上运行,我们期望看到高可变性的成功。在许多 git-flow 模型中,主题分支是大部分工作完成的地方,因此也是大部分信号生成通过和失败实验的地方。
通过对主题分支的特性开发进行范围界定,我们可以区分有意的实验(失败的构建是有价值的和预期的)和稳定性问题(失败的构建是不受欢迎的)。默认分支的成功率比主题分支的成功率更有意义。
为您的团队设定 DevOps 成功基准
虽然没有每个团队都应该向往的通用标准,但我们的数据和我们在平台上观察到的软件交付模式表明,对于团队来说,有合理的工程度量来设定目标。最终,你测量基线并逐步改进这些指标的能力比追求“理想”数字更有价值。
了解有关如何通过我们的 2020 年数据报告衡量开发运维成功的更多信息
下载 2020 年软件交付状态:面向工程团队的数据支持基准了解您和您的团队如何在未来扩大您的软件交付。在这里下载的报道。
如何通过 CircleCI 输出 JUnit 测试
原文:https://circleci.com/blog/how-to-output-junit-tests-through-circleci-2-0-for-expanded-insights/
来自出版商的说明:您已经找到了我们的一些旧内容,这些内容可能已经过时和/或不正确。尝试在我们的文档或博客中搜索最新信息。
CircleCI 提供了关于您的工作和测试性能的有用信息。它可以告诉你最后一次运行的时间、平均工作时间、排队时间和成功率,以及一些帮助你可视化的图表。
这是所有项目一开始的样子。
有多少次你想知道:我的哪些测试失败了?我的哪项测试最失败?我失败的测试中哪一个运行最慢?
CircleCI 也可以帮你。让我们看看在哪里可以找到这些信息!
失败和最慢的测试
Insights 不仅可以给我们一个测试套件失败的概要,还可以通过测试名称甚至失败的频率来分解它。如果你有古怪的测试或一些严重的惯犯,他们会在这个列表中给你检查和挤压。与频率数据类似,Insights 还可以为您提供失败时哪些测试耗时最长的排名。这些数据有助于您轻松发现可能会超时的测试。
那么我们在哪里可以找到这些数据呢?如果你和我一起在洞察力页,你已经在那里。我们需要做的就是向下滚动:
你可能会问,“杰森,数据在哪里?”在我们释放洞察力的全部潜力之前,我们需要做一点准备。所需的步骤取决于您的设置,但是对于我们的示例,只需要两步。我们一起去看看吧。
释放力量
测试
对于本文,我写了一个演示项目,在 Cucumber 和 Ruby 的 RSpec 中运行一些非常基本的“测试”。每个工具都有一组相同的三个测试:
- 总是传递-断言 true 为真。
- 频繁传递-生成一个随机数,并断言它是否小于阈值。目前 0.95。
- 不太频繁通过-与之前的测试相同,但其阈值设置为 0.85。
这将给我们带来一些间歇性的测试失败,给我们的测试结果带来一些可变性。如果你很好奇,以下是步骤定义的样子:
Given('this step passes') {}
Given('this step often passes') do
expect(Random.new.rand(1.0)).to be < 0.95
end
Given('this step less often passes') do
expect(Random.new.rand(1.0)).to be < 0.85
end
朱尼特
我们需要做的第一件事是让我们的测试工具以 JUnit XML 格式输出。什么是 JUnit XML?JUnit 本身是 Java 编程语言的单元测试框架,它以 Apache Ant JUnit XML 格式输出结果。如果您不是 Java 开发人员,这也完全没问题,因为跨语言的工具实现自己的格式化程序是很常见的,这些格式化程序遵循 JUnit XML schema 。对于我们的例子,我将展示如何为 RSpec 和 Cucumber 这样做,但是 CircleCI 提供了一个其他通用选项的列表,您也可以使用。
这里有一个示例.circleci/config.yml
文件,我们将一起修改它以获得更好的洞察结果:
version: 2.1
executors:
default:
docker:
- image: circleci/ruby:2.5
commands:
install_gems:
description: "install dependencies"
steps:
- run: bundle check --path=vendor/bundle || bundle install --path=vendor/bundle --jobs=4 --retry=3
rspec:
description: "Run RSpec"
steps:
- run:
command: bundle exec rspec
when: always
cucumber:
description: "Run cucumber"
steps:
- run:
command: bundle exec cucumber
when: always
jobs:
test:
executor: default
steps:
- checkout
- install_gems
- rspec
- cucumber
workflows:
pr:
jobs:
- test
这是一个 2.1 配置,但不要让这吓到你,我们在这里做的是在较低的版本中也可用。
现在,我们对 RSpec 和 Cucumber 的命令非常简单:分别是bundle exec rspec
和bundle exec cucumber
。这允许工具将它们的结果输出到 stdout,这样它们就可以使用它们的默认格式。这对于在本地运行来说很好,但是当您想要轻松地看到工作流在 CircleCI 上运行时发生了什么故障时,这就不太好了。对于我们总共六次测试,读取控制台的测试输出不会太差,但是对于较大的测试套件,这可能是一项困难的任务。
这两个工具都允许非常容易地以 JUnit 格式输出。
RSpec
- 将
rspec_junit_formatter
宝石添加到您的宝石档案中。 - 将
--format progress --format RspecJunitFormatter -o ~/test-results/rspec/rspec.xml
添加到 RSpec 命令中。
注意:不需要初始的--format progress
,但是如果不保留的话,RSpec 只会输出到 rspec.xml 文件,而不是 stdout。黄瓜也是一样。
黄瓜
- 将
-f pretty -f junit -o ~/test-results/cucumber/cucumber.xml
添加到您的黄瓜命令中。- 虽然 Cucumber 会为您运行的每个特性文件创建 XML 文件,但是我们仍然希望在路径的末尾有
cucumber.xml
。
- 虽然 Cucumber 会为您运行的每个特性文件创建 XML 文件,但是我们仍然希望在路径的末尾有
下面是我们更新的.circleci/config.yml
:
version: 2.1
executors:
default:
docker:
- image: circleci/ruby:2.5
commands:
install_gems:
description: "install dependencies"
steps:
- run: bundle check --path=vendor/bundle || bundle install --path=vendor/bundle --jobs=4 --retry=3
rspec:
description: "Run RSpec"
steps:
- run:
command: bundle exec rspec --format progress --format RspecJunitFormatter -o ~/test-results/rspec/rspec.xml
when: always
cucumber:
description: "Run cucumber"
steps:
- run:
command: bundle exec cucumber -f pretty -f junit -o ~/test-results/cucumber/cucumber.xml
when: always
jobs:
test:
executor: default
steps:
- checkout
- install_gems
- rspec
- cucumber
workflows:
pr:
jobs:
- test
下面是我们的 RSpec 测试的 XML 输出示例,显示前两个测试通过,第三个测试失败:
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="rspec" tests="3" skipped="0" failures="1" errors="0" time="0.017001" timestamp="2019-01-24T22:17:57-07:00" hostname="JS-PC">
<properties>
<property name="seed" value="29522"/>
</properties>
<testcase classname="spec.demo_1_spec" name="demo 1 with tests for demonstration always passes" file="./spec/demo_1_spec.rb" time="0.001000"></testcase>
<testcase classname="spec.demo_2_spec" name="demo 2 with tests for demonstration sometimes passes" file="./spec/demo_2_spec.rb" time="0.001000"></testcase>
<testcase classname="spec.demo_3_spec" name="demo 3 with tests for demonstration more often passes" file="./spec/demo_3_spec.rb" time="0.014001"><failure message="expected: < 0.85
got: 0.9199158781050316" type="RSpec::Expectations::ExpectationNotMetError">Failure/Error: expect(r.rand(1.0)).to be < 0.85
expected: < 0.85
got: 0.9199158781050316
./spec/demo_3_spec.rb:8:in `block (3 levels) in <top (required)>'</failure></testcase>
</testsuite>
完成这些更改后,第 1 步就完成了!🎉继续第二步。
你的 JUnit 测试文件在哪里?
我们已经让我们的测试工具以正确的格式输出,他们正在将输出保存到我们项目的文件中。下一步是通过告诉 CircleCI 在哪里可以找到它们来使用它们。这是通过内置命令store_test_results
完成的。
命令store_test_results
接受一个路径,是我们对 CircleCI 说,“嘿,这是我的测试数据。”我们希望确保这个路径与我们的命令保存文件的路径相同。这个路径值可以是绝对或相对,但是注意,如果你使用的是相对位置,它是基于你当前的工作目录。
下面是在我们的配置中将store_test_results
步骤添加到命令中的样子:
rspec:
description: "Run RSpec"
steps:
- run:
command: bundle exec rspec --format progress --format RspecJunitFormatter -o ~/test-results/rspec/rspec.xml
when: always
- store_test_results:
path: ~/test-results/rspec/
cucumber:
description: "Run cucumber"
steps:
- run:
command: bundle exec cucumber -f pretty -f junit -o ~/test-results/cucumber/cucumber.xml
when: always
- store_test_results:
path: ~/test-results/cucumber/
强尼,给他们看看他们赢了什么!
一辆全新的摩托车-不!不是新的踏板车,而是一些有用的数据,可以帮助我们了解测试套件的进展情况。现在让我们试着向下滚动我们的见解页面:
请击鼓……
很好,我们做到了!给定测试结果数据,CircleCI 将自动开始分析并为我们显示这些数据。如前所述,Insights 可以向我们显示关于最失败的测试、它们的套件、失败频率的数据,以及关于我们最慢的失败测试的类似数据。测试套件下的名称根据工具的不同而不同,Cucumber 输出特性名称,RSpec 使用包含 Spec 文件文件名的名称。
这里有一个稳定的图像,这样你可以看到更多:
但是等等,还有呢!
Insights 页面并不是从存储测试数据中获益的唯一领域。默认情况下,jobs 中的测试摘要选项卡只会显示一个按钮,指向store_test_results
周围的文档。
随着见识的扩大,我们的总结现在也是如此。如果测试在您的工作中失败,围绕这些失败的数据将在信息框中向上冒泡,如下所示:
这些框会告诉你什么工具和特定的测试失败了,以及关于断言的一些信息。如果一个特定的工具有多个故障,为了便于查看,它们将被分组在同一个框中。蓝色的查看大多数失败的测试按钮将带您直接进入 Insights 页面。
如果您的所有测试都通过了,您还将获得一些汇总数据,包括关于运行了多少测试以及使用了什么工具的注释。
注意:为了确保您不会看到类似“您的作业在未知的情况下运行了 6 测试”的消息,您需要确保您正在为您正在使用的每个测试工具创建目录,如下所示:
test-results
├── cucumber
│ └── cucumber.xml
└── rspec
└── rspec.xml
如果你正在遵循上面的例子,我已经为你做好了准备,所以你不应该对unknowns
的出现有任何问题。
两步走方法
- 以 JUnit 格式输出测试结果
- 用
store_test_results
命令告诉 CircleCI 那些结果在哪里
这两个简单的步骤使 CircleCI 能够为我们提供丰富的信息,以及对我们测试的健康和性能的更深入的了解。现在,您已经有了从现在开始将测试结果存储在您的config.yml
文件中的工具,我强烈推荐您这样做。
Gemini Smith 是一名不断学习的软件工程师,对测试、交流和改进软件开发生命周期充满热情。主要用 Go 写作,她还通过公开演讲、宣传、咨询和指导对软件和测试社区做出贡献。
CircleCI 如何利用客户反馈来发布更好的产品
原文:https://circleci.com/blog/how-to-run-a-customer-focused-product-launch/
作为一个开发者工具,CircleCI 有着独特的定位,拥有优秀的客户群。我们的顾客很聪明。它们具有无限的创造力,有时会以我们设计系统时没有想到的方式给我们带来惊喜。这既是福也是祸。在诅咒的一端,令人难以置信的发明优势案例的长尾可以将简单的任务转化为西西弗英雄的旅程。当我们处理这样的请求时:“请重构代码库,使用 Golang 的 git 实现,而不是当前特定于操作系统的 blend,”我发现自己在思考这幅漫画:
尽管复杂,客户反馈的好处远远超过成本。我们客户的观察很详细。他们的请求是由他们自己处理产品规范和构建应用程序的经验决定的。我们注意到他们的专业知识带来的优势,并努力在发布周期收集他们的意见。以防我对我们以客户为中心的发布过程的价值有任何怀疑,我们最近的 Windows 版本以我从未预料到的方式证明了它的重要性。
将客户反馈纳入我们的发布周期
在 CircleCI,新产品经历了一系列的发布阶段,这些阶段鼓励客户的投入和审查,以帮助我们在产品发布时对其进行微调。我们已经成功利用这些阶段推出了球体、视窗(详见下文!),很快我们就有了新的 GPU 资源类。
一旦我们完成了功能性概念验证,我们的发布故事就开始了。从那时起,该流程将经历以下六个阶段:
-
内部发布:狗粮。我们永远是自己的第一批顾客。我们继续在产品的整个生命周期中使用我们自己的产品。
-
预览发布。在我们对初步的架构良好且功能有限的【WAFL】产品能够提供价值感到满意后,我们将向一组有限的自选客户开放,这些客户普遍对新功能感兴趣。我们将预览文档曝光给这个小组。
-
出血边缘改善(周期)。当有限客户群提出问题时,我们会解决它们,做出改进,并重复。他们处于我们产品的最前沿,虽然产品对他们来说足够有用,可以让他们实现价值,但也有粗糙的边缘。
-
无声发射。当我们的 WAFL 最粗糙的边缘被移除后,我们悄悄地向我们的整个客户群开放该产品的使用。发现新功能的客户往往会积极寻求其功能。这些勇敢的探索者被激励着让它为他们的特定用例工作,并且经常分享关于他们在实现他们难以捉摸的第一个绿色构建时遇到的障碍的强烈意见。当我们进行最粗略的改进时,引入问题的严重性会下降;这是更传统的软发布(向有限的观众发布产品的预览版)开始的时候。
-
粗糙边缘改善(循环)。随着这个更大的客户群体提出问题,我们看到了积极性高的用户遇到的困难,我们会首先解决这些困难。一波又一波的客户反馈帮助我们将痛点缩减为挥之不去的“颠簸”体验的有限列表,为产品的全面发布做好准备。我们与我们的支持团队讨论任何遗留问题(通常是 UX 关注的问题),为发布做准备。
-
正式上市!比赛日。我们舒适地拿着寻呼机,最后一次回顾优先问题清单。我们清楚地知道哪些方面可能会令人失望,哪些方面会带来喜悦,以及我们可能需要在哪些方面对问题进行分类。
在整个过程中,我们从早期采用者那里获得了非常有价值的、有针对性的反馈。有时,他们甚至为我们调试问题。最重要的是,他们的反馈提供了细致入微的方向,让我们对最终产品的适合度充满信心。我们的 Windows 产品展示了这些优势。
客户对成功的反馈(dows)
当我们在 2019 年 1 月开始构建对 Windows 的支持时,我们的五人团队很快就冲刺到了概念验证。在其他保持照明的工作中,我们去了一家 WAFL,很快就遇到了我们的第一个问题。为了启动我们的 Windows 预览版,我们需要一种方法来支持这种新资源的容量需求,而当时,我们还没有自动资源扩展功能。如果没有自动缩放,我们面临三种选择,我们可以:
-
过度配置计算(保持虚拟机预热以避免客户启动过多的虚拟机时间),CircleCI 的资金成本很高。
-
少量调配计算资源并将 SLA 违约与我们的随叫随到轮换联系起来,对开发人员来说成本很高,或者
-
不调配计算资源,让客户忍受缓慢的虚拟机调配时间。
我们最终决定扩大我们的资源规模,为我们的工程师提供最佳的用户体验和最低的维护开销。
随着我们的预览版发布畅通无阻并在后台运行,我们开始稳定我们的计算系统。五名工程师加入了我们的团队,我们十个人开始在新的(对我们来说)系统中寻找前进的最佳路径。我们管理我们的 Mac 机队和映像发布周期,开始通过构建断路器来提高我们的云提供商的容错能力,研究排队论并开始实施自动扩展;Windows 的新功能开发在很大程度上被搁置了。
它没有被完全遗忘。当我们其余的人致力于改进我们的系统时,来自原始团队的一个工程师一点点地解决来自预览版用户的问题。Windows 的使用也在增长。几个月后,我们悄悄地取消了选择加入的限制。到夏末,我们在资源使用仪表板上看到了一个有规律的、循环的构建周期,这是一个特性牵引力已经达到的指标。
然后,我们宣布了 Windows GA 的发布日期,我们的时间表从几个月变成了几周:它将在 25 天内完成。
作为工程经理,我为我们如何取得成功制定了一个计划,这个无声的启动成了我的基石。我们已经沉默了几个月了。我们知道我们的早期采用者感受到的挥之不去的油漆点,我们知道他们欣赏的功能。
很难表达对我和我的团队来说,回顾我们无声启动的结果,能够快速而自信地清楚了解我们在哪里,以及在启动前的几周内我们需要完成哪些杰出的工作,是多么轻松。尽管我们的团队承担了许多新的职责,改变了关注的领域,并快速引入了发布日期,但当 GA 推出时,我们对我们产品的优势和局限性充满信心。从产品完整性的角度来看,我们已经处于有利位置。
在发布日,我们用汗湿的手掌紧握着传呼机。我们从来不需要它们。我们的断路器解决了一个供电中断的问题,新完成的自动秤进行了缩放,我的血压也正常了。
结论
即使是计划最好的功能发布也令人望而生畏,并包含一定的希望因素。虽然希望当然是一种启动策略,但我并不推荐它作为一种策略。为了提高我们团队的信心和我们的产品,我们通过一系列越来越公开的发布,在开发周期中尽早并经常纳入客户反馈。你也可以。
由于我们以客户为中心的战略,我们能够满怀信心地推出 Windows:
-
我们已经彻底地生产测试了我们的代码。
-
我们已经在开发过程的早期解决了最紧迫的问题。
-
我们已经取得了特色牵引。
我们非常感谢用户提供的反馈,我们永远欢迎评论和建议。
想投稿?在此与我们分享您的想法。
如何在 CI/CD | CircleCI 上销售您的经理
原文:https://circleci.com/blog/how-to-sell-your-team-on-ci-cd/
持续集成似乎是一个明智的选择,对吗?为什么会有人认为尽快将你的代码集成到产品中是个坏主意?
让我带你回到 2000 年 8 月,当时一位年轻的工程师刚刚开始她的第一份工程工作。她得到了一张桌子、一台电脑和一份详细的项目计划,其中包括未来三个月的发布日期。当她写代码的时候,QA 工程师正忙着写测试计划,为发布候选做准备。
经过四个月的艰苦工作,工程师和她的团队将他们的代码发送到 CD-ROM 工厂,该工厂将打印 CD-r om 发送给客户。许多客户都在急切地等待这个软件的新版本。距离上一次更新已经过去了八个月,他们六个月前报告的 bug 开始让他们烦恼。
上面的故事是我对软件工程入门的真实描述。当时,更新软件的成本是巨大的。这需要很长的测试周期和大量的艰苦工作来确保文档的准确性——截图可能会很快过时,但文档在软件发布后无法更新。
对产品做出改变是困难的,而且犯错的代价也很高。
CI/CD 的独特优势
今天,事情有了很大的不同,这主要归功于持续集成和持续交付(CI/CD)。
很难夸大能够在产品准备好的时候就做出改变的强大影响。工程师和客户之间的反馈回路要短得多,作为工程师,我们可以以把客户放在第一位的方式来回应客户的反馈。
降低向客户交付变更的成本意味着我们可以快速回滚我们引入的任何错误。这也意味着在进行以前看起来有风险的变革时有了更多的信心。一次引入一个变化也有助于避免那些在最后一刻将两个特性推到一起时难以发现的错误。
事实上,你可以通过不断的改变来获得更高质量的产品,这看起来似乎是违反直觉的,但是在现实中,这是改进的唯一方法。
那么,你对一个对 CI/CD 持怀疑态度的管理者说些什么呢?以下是您的经理可能会问的一些问题的潜在答案:
注意不要说一些类似于“尽可能快地将代码投入生产”的话来吓到你的经理
这可能会被理解为将未完成的或损坏的功能放在客户面前,但事实并非如此。一个好的答案可能是类似于这样的话,"持续集成是将我们的工作分成小块,与我们的同事分享我们的工作,并经常问答。"
CI/CD 的成本是多少?
转移到 CI/CD 的成本取决于您愿意在伟大的自动化测试上投资多少。正因为如此,成本会随着你在测试过程中的进展而变化。如果您手动进行大部分或全部测试,成本可能会比您拥有一套丰富的自动化测试(包括端到端测试)更高。
投资自动化测试是很容易的。在 CI 工具上运行自动化测试比雇佣工程师做同样的事情花费更少,也更可靠。请注意,你是在要求你的经理用特性交付来抵消这个价值,这可能是一个艰难的决定。预计您的经理将希望逐步增加自动化测试,并可能在部署之前增加一个手动 QA 步骤——这是许多团队为了实现 CI/CD 而采取的步骤。
Life Pro 提示:如果你的经理问你 CI/CD 的价格,而你回答团队将花费多少季度,他们会更认真地对待你。
投资 CI/CD 有什么好处?
虽然我确信每个经理都在为他们的工程师的幸福投资——我知道我是——但很少有经理能够花费大量时间专门让他们的工程师幸福。是的,CI/CD 是一项伟大的投资,因为它使您的开发人员的工作更加愉快,但是工程师的快乐仅仅是一项伟大的商业决策的副作用。
CI/CD 还有许多好处,这些好处超越了工程师的快乐,真正证明了投资的合理性。
- 对于多个团队成员来说,在同一个特性上工作要容易得多。
- 合并小变更的成本比大变更低得多。
- 团队成员可以在一个已经通过自动化测试的系统中评估他们同事的变更,而不是一个特性分支的移动目标。
- 对于 QA 工程师来说,在一个一致的系统中迭代地验证小的变化要容易得多,因此检测错误的来源变得简单得多。
- 功能可以在更早的状态下到达客户手中。这意味着,如果我们在错误的轨道上,我们可以在少量投资后改变方向。
与领导价值观保持一致,以获得 CI/CD 的“肯定”
作为工程师,我们知道 CI/CD 是有意义的。这意味着代码质量更高,功能交付更快。它在我们的产品代码中引入了一种信心,这种信心在特性被集成并在它们被编写之后很久才交付时是不存在的。
对一些经理来说,这可能感觉不直观。为了让你的经理接受 CI/CD,你需要使用符合他们价值观的语言和想法。希望这篇文章能提供一个好的起点。
如何为 Rails 双引导设置持续集成管道
原文:https://circleci.com/blog/how-to-set-up-a-continuous-integration-pipeline-for-a-rails-dual-boot/
自从 GitHub 和 Shopify 使用双引导策略将他们的 Rails 应用程序从旧版本的 Rails 转移到 Rails Edge 上运行以来,双引导策略一直是一种流行的升级方法。Shopify 在他们的 Rails 5 升级中展示了这一策略,GitHub 在 2018 年从 Rails 3.2 升级到 5.2 时也类似地解释了他们的策略。
双重引导的好处之一是,您可以增量升级,并且您的整个开发团队不需要停止构建新功能。也不需要单独的长期升级分支。升级的每个部分都可以被视为一个基于主分支的小工作单元。除非您要求,否则它不会在您的服务器上运行。
在 Planet Argon ,一个专注于 Rails 支持的机构,我们使用这种更新方法,并希望通过本教程分享我们的技术。它将通过一个开源的 Rails 应用程序自行车索引来演示。自行车索引是一个自行车登记工具,帮助重聚失踪和/或被盗的自行车与他们的主人。我们有两个原因很高兴使用这项服务作为例子:该公司也位于波特兰,我们的工作室有一些骑自行车通勤者,包括我自己。
在本教程中,您将学习如何使用 ten_years_rails gem 在您的应用程序中加入双重引导,并重新配置现有的 CircleCI 配置以支持双重引导的 CI 运行。
当您的应用程序的自动化单元和集成测试覆盖了您的代码库的很大一部分时,您可以通过在双重启动的升级端通过测试的数量来衡量您的升级进度。许多应用程序使用持续集成 (CI)工具来运行他们的测试套件,本演练将把双重引导过程集成到您的 CI 管道中,以快速确定新的更改是否影响当前版本或升级版本。
作为一个高层次的概述,这里有一个 PR ,其中进行了一些更改,以使 Bike Index 的 CI 管道运行一个双启动流程。
先决条件
要完成本教程,您需要以下内容:
- 带有测试套件的 Ruby on Rails 应用程序
- 应用程序的现有 CircleCI 配置
我们开始吧!
更新您的 Gemfile
首先,我们将安装ten_years_rails
gem 来设置我们的双重引导。使用此宝石需要 Ruby 2.3 或以上版本。将以下内容添加到您的 gem 文件中:
gem 'ten_years_rails'
gem 包括一个“next”脚本,允许您在命令之前运行next
,以便在升级的环境中测试它们。通过运行next --init
初始化 gem。这将创建一个名为Gemfile.next
的符号链接 Gemfile。
捆绑我们的宝石
现在让我们确保我们可以捆绑我们的宝石。
ten_years_rails
通过在两个不同的 gem 文件之间交替工作:应用程序中已经存在的标准 gem 文件和符号链接的Gemfile.next
。进入Gemfile.next
包的内容基于next?
方法。
我们的主要目的是升级 Rails。要指定放入Gemfile.next
的版本,编写如下条件:
if next?
gem 'rails', '~> 6.0', '>= 6.0.2.1'
else
gem 'rails', '5.2.4'
end
任何在if
语句下安装的 gems 都将被安装在符号链接的Gemfile.next
中,并且可以通过检查Gemfile.next.lock
版本来验证。else
语句中的宝石将被安装在Gemfile.lock
文件中。
然后运行:
next bundle install
如果您在使用next
命令时遇到麻烦,您还可以传递BUNDLE_GEMFILE=Gemfile.next
环境变量来指定在您当前的上下文中应该使用哪个 gem 文件。可能还有其他需要升级的依赖项。
我们不打算深入探讨这个问题,但是我学到的一个技巧是,需要升级的宝石可能没有你想象的那么多。不要被这个 bundler 输出吓倒。寻找版本与你正在做的不匹配的 gem,并为该版本创建一个条件。将它们的安装命令包装在next?
条件中。
最初的测试可以是安装没有版本限制的 gem,让 Bundler 为您选择版本。
if next?
gem 'devise'
else
gem 'devise', '~> 3.5', '>= 3.5.10'
end
设置您的 CI 渠道
一旦您的包成功安装,我们就可以启动并运行 CI 管道了。我们也可以进行测试,但在这一点上,没有必要。我们只是希望管道可以在两个独立的版本中运行在两个版本的 Rails 上。如果 RSpec 暂时惨败也没关系。
策略是使用工作流添加一个新的作业来使用Gemfile.next
运行 rails 的下一个 CI。
复制您现有的构建作业,并为该副本命名,以表明它是用于双引导的。我们选择了build-rails-next
。
在build-rails-next
作业中,您将在BUDNLE_GEMFILE
的ENVIRONMENT
键下添加一个键/值对,并指定Gemfile.next
。
"build-rails-next":
working_directory: ~/bikeindex/bike_index
parallelism: 2
environment:
RAILS_ENV: test
NODE_ENV: test
RACK_ENV: test
BUNDLE_GEMFILE: Gemfile.next
然后,在保存和缓存捆绑的 gem 的命令中,将文件更改为Gemfile.next.lock
- type: cache-restore
name: "Ruby dependencies: cache restore"
key: cache-{{ .Environment.CACHE_VERSION }}-gems-{{ checksum "Gemfile.next.lock" }}
- run:
name: "Ruby dependencies: install"
command: |
set -x
bundle check --path=~/.cache/bundle && use_local="--local"
bundle install --deployment --frozen --path=~/.cache/bundle $use_local
- type: cache-save
name: "Ruby dependencies: cache save"
key: cache-{{ .Environment.CACHE_VERSION }}-gems-{{ checksum "Gemfile.next.lock" }}
paths:
- ~/.cache/bundle
最后,在配置底部的 workflows 部分调用新的构建作业:
workflows:
version: 2
commit:
jobs:
- build
- "build-rails-next"
您可以通过运行circleci local execute
使用 CircleCI 的 CLI 来测试您的更改。但是,如果您没有看到新的构建作业,您可能需要推动您的更改以使其工作。
我尝试使用本地 execute 方法来测试我的更改并遇到了错误,所以我在一个新的 commit 中向上推它们,并去 CircleCI 的网站检查这些更改。
您应该在 CircleCI 上看到两个构建任务,一个用于您的常规任务build
,一个用于build-rails-next
。
为了确认一切正常,检查安装在每个版本上的宝石,确保它们是正确的。在我们的示例中,build
安装actionview 5.2
,build-rails-next
安装actionview 6
。
你的 Rails 5 版本,没有被双引导改变所干扰,应该会完美地通过,而你的 Rails 6 版本将会光荣地失败。
结论
就是这样!现在,您可以开始 Rails 应用升级之旅了。继续修正规范、重构代码、咨询 CI 渠道,并利用next?
方法来保持当前代码运行,并将升级代码合并到流程中。Rails 升级可能很困难,但是利用双引导方法可以提供一些结构。
升级快乐!
Kayla Reopelle 是 Argon 星球的开发人员。她最喜欢的 web 开发部分是重构遗留代码,使其更易于维护,并使非开发人员也能理解编码概念。工作之外,你可能会在波特兰的一条小径上骑自行车长途跋涉时偶遇她。
如何在开发者大会上开始演讲
原文:https://circleci.com/blog/how-to-start-speaking-at-developer-events/
科技活动演讲实用指南
如果你曾经看过一个会议或 meetup 的发言人阵容,并认为,“嘿,我可以这样做!”然后想,“但是等等……我该怎么开始呢?”那么这篇文章是给你的。
在科技活动上发表演讲是许多技术专家的目标,这是有充分理由的:这是结识志趣相投的人的好方法,可以提升你在特定社区的形象,提高你讲故事和技术的能力。
我们为 CircleCI 的内部员工编写了这份介绍,并意识到许多提示和指南可能对更广泛的受众有用。有更多提示吗?你觉得我们错过了什么吗?让我们知道。
就这样,让我们开始我们的演讲指南吧。
第一步:从目标开始
你应该清楚地知道你想通过演讲达到的目标。他们是:
- 分享你对特定技术的热情
- 帮助别人从你的错误中学习
- 打造你的个人品牌
- 招募人们来你的团队工作
- 获取销售线索
- 在大型行业活动中获得公司品牌曝光率
- 向目标受众宣传您的解决方案
还有别的吗?什么?
会谈需要很多时间和精力。有经验的演讲者通常估计每一个小时的演讲要准备 40 个小时。确保你知道你希望从中获得什么。
步骤 2:选择要提交的事件
一旦你心中有了目标,是时候去寻找那些可能会让你感兴趣的场所和活动了。虽然像 re:Invent 这样的大型科技活动得到了很多关注,但最好先从本地聚会和小型会议开始。Papercall.io 和 Meetup.com都是寻找可能对你要说的内容感兴趣的事件的绝佳资源。
第三步:写一份建议书
在你确定了一个你想演讲的事件后,是时候把你的演讲想法变成一个提议了。以下是一些写好建议书的技巧:
- 看看去年接受了什么。前几年会议的报告是组织者感兴趣的内容的小抄。不要试图重复主题或内容,但一定要看看他们对演讲者的专业技术水平和讲故事的期望。
- 阅读提交表格。如果有多页,点击浏览,将你需要回答的所有问题提取到一个文档中。没有什么比在截止日期前提交并意识到有一大堆你没有计划的额外的强制性问题更糟糕的了。
- 给组织者他们想要的!如果他们要求安全案例,提交安全案例。他们会给你一个主题列表,因为他们可能有他们想要填充的曲目或内容类型。不要指望他们会把菠萝对话放进蔬菜对话展示中。
- 早点提交。至少提前 2 周提交。为什么?每个人都在最后一刻申请。尽早申请意味着有人会阅读你的提议并加以考虑,然后用你的提议和其他人进行比较。你越早申请,就越有可能参加会议。值得一提的是,这也适用于那些申请 T2 大学提前录取的人。
- 最多提交两次演讲。提交更多的内容会让评审者感到沮丧,这表明你很难编辑你的想法。
- 你需要视频吗?这可能很难找到!如果你没有自己演讲的录音,可以录一段内部技术演讲(经过许可)或者一段视频教程。你也可以录下自己排练演讲的过程。组织者通常会寻找一些关于提交者演讲风格的参考,在大多数情况下,这些排练视频就足够了。
- 写一个好标题。这是战斗的 75%,不应该是事后的想法。当我告诉你把大部分时间花在标题上时,我不是在开玩笑。一个好的标题表明你有一个简洁的想法。标题是让人们听你演讲的东西。
请注意,这里的步骤 1-3(确定你的目标,选择一个活动,写一份建议书)的顺序有些随意。你可能有一个很棒的成功故事想要分享,所以你寻找可能对那个故事感兴趣的相关事件。或者你的老板说,“我需要你提交 GitHub Universe”,你从这个目标开始倒退。
第 4a 步:你被拒绝了。现在怎么办?
如果你的提议被拒绝,振作起来:在大型活动中,这是最有可能的结果。例如,KubeCon EU 今年收到的谈判数量是他们有余地接受的数量的 7 倍。竞争激烈!
如果你没有得到任何反馈,可以考虑向组织者寻求反馈。礼貌点!但是来自会议组织者的反馈可能是黄金。
这里有一个写什么的例子:
“您好[演讲组织者姓名],联系我提交的[会议]演讲材料[标题]。我知道今年提交了许多特别的演讲,我很高兴看到阵容/对发布的阵容感到兴奋,特别是[XYZ 演讲日程]。我期待着参加您的活动!如果你有任何反馈(无论多么简短),可以分享一下为什么我的演讲没有被接受,我会觉得非常有用。我正在努力写更好的提交材料,并寻找更多的机会来展示,你可以分享的任何见解都将极大地帮助我实现这些目标。如果有什么我能做的来支持这次活动,请不要犹豫。
感谢您的反馈,
人类”
如果他们没有回信,就不要跟进——随它去吧。当谈话阵容发布时,将你的提交与被接受的进行比较,并尝试提出一些你认为你不成功的原因。
除非你是埃隆·马斯克,否则你可能只有 25%的成功率。不要难受!如果你总是被接受,你没有申请足够大的场地,或者你是凯尔西·海托华。
第 4b 步:你被录取了!现在怎么办?
祝贺你,你的演讲被接受了!
暗示焦虑:现在你需要一个演示。一种方法是写一个演讲内容的大纲,然后通过写画外音音轨来填充大纲。用脚本写一篇演讲帮助我评估流程,并确保所有的关键点都被击中。这也有助于把握谈话的时机。
这里有一个如何做到这一点的例子。写下你的提纲,然后建立一个文档,在那里你可以写下你的演讲主题和你认为可能的视觉效果。
例如:
幻灯片 11:标题:关于兔子要记住的 3 件事
可能的视觉效果:3 只头上有文字的兔子
画外音:如果你从这次演讲中只学到 3 件事,我想让你记住的是:1。兔子很可爱。2.兔子毛绒绒的。3.兔子喜欢胡萝卜。
每个人都有自己喜欢的不同的概述方式,但是在你写下你的叙述之前,不要沉迷于幻灯片的设计或格式。一个好的故事可以用非常简单的幻灯片设计来独立存在。试着不要把视觉效果想得太紧,直到你把文字勾勒出来,这样你就可以在陷入滑梯兔子洞太深之前检查一下流程。
你应该如何组织你的演讲?
虽然有无数种方式来组织演讲,但是有一些经典的方式可以帮助你思考如何讲述你的故事。
1。有说服力的论点第一种是有说服力的形式,你可以在演讲、写作或者任何你需要说服某人的时候使用。这真的很简单,也是一个很好的组织思想的框架:
- 有什么问题?
- 为什么会有问题?
- 有什么解决办法?
- 为什么你的解决方案是最好的解决方案?
下面是这种格式在实践中的一个例子:
- 有什么问题?
- 我们的网络连接太慢了。
- 为什么会有问题?
- 缓慢的互联网速度使开发人员无法跟上潮流,因此他们的工作效率低于预期。等待文件下载或页面加载纯粹是停机时间,工程师在这段时间里没有其他有意义的事情可做。由于员工成本是我们的最高成本,我们所能做的任何有助于提高我们团队生产力的事情都是值得的。如果我们相信最好的工具和设备会有所作为,我们就应该投资它们。最后,缓慢的互联网让我们的团队感到沮丧。他们想要建设,而不是等待。
- 有什么解决办法?
- 我们可以做一些事情。我们什么也做不了,只能接受这是做生意的成本。我们可以给办公室增加一条新的光纤线路。或者,我们可以使用无人机将路由器悬停在天花板附近,从而增强整个办公室的信号。
- 为什么你的解决方案是最好的解决方案?
- 什么都不做将会导致我们的竞争对手超过我们,我们的团队会沮丧地退出。光纤会加快我们的连接速度,但我们的大楼里没有,我们也无法控制什么时候会有。购买无人机在我们的办公室飞行路由器将使用现有设备以低成本增强我们的信号,同时也娱乐我们的同事,并表明我们是一个创新、令人兴奋的工作场所。随着时间的推移,我们可能会遇到一些办公室安全和损坏设备的问题,但增加的生产力收益应该值得偶尔发生的办公室无人机碰撞。
有说服力的论证格式需要注意的一点是,确保它不会无意中变成演示或推销。
如果你打算在你的演讲中包括一些现场编码或演示,你应该在你的提交摘要中提到这一点。以下是一些措辞示例,表明了在演讲提交中使用实时代码或演示的意图:
- “在本次演讲中,Emma 将展示开发人员如何在其 CI/CD 管道中轻松配置和使用 Docker 容器。”
- 在本演示结束时,与会者应该对如何在 CircleCI 平台中使用 cypress.io 从 CI/CD 管道中测试 node.js 应用程序有了深入的了解。
产品演示或推销是不再被邀请在会议上发言的最快方法。
2。我学到了什么
“我学到了什么”是最常见的谈话类型,可以应用于从技术深度探讨到高级战略会议的任何内容。这是讲故事的好方法,通过开放的对话和诚实来建立共鸣。你会经常看到这种类型的演讲,题目是“你应该做的 5 件事”或者“我们为什么跑步…”或者“如何知道什么时候…”
下面是一个典型的“我学到了什么”的概要:
- 自我介绍和公司介绍
- 设置情景:作为一个团队,你们在哪里?发生了什么事?
- 发生了什么让你意识到你需要改变?
- 你尝试了什么?
- 什么奏效了?
- 你现在做什么?
- 如果你实现了这一点,你应该做这些事情而不是那些事情。
关于此格式的警告:
- 你不想在这里说得太笼统或者太明显,以至于听众在你演讲的时候会认为,废话
- 你不想说得太具体,以至于听众不明白你所说的任何事情如何适用于他们
这听起来可能很明显,但这是一个非常棘手的平衡。分享适当的背景,增加幽默和轻松,对你的思考过程和决策过程保持透明会有所帮助。
这种格式也很适合一些不同的口味:
- “传统智慧说 X,但这就是为什么这对我们不起作用”又名“这就是为什么我们做出这个疯狂的决定,为什么它可能对你起作用,也可能不起作用!”
- “我们错了 7 次,我们学到了什么”
- “我以为我知道的关于 X 的一切都是谎言!”
3。数据深度挖掘
啊,数据深度潜水。会议空谈主义的圣杯!你有数据支持你的决策和结论吗?你赢了。这可能也是最难整合的格式。像这样的演示文稿的一些常见格式是:
- “100 万个构建输出错误表明这是 3 件最重要的事情”
- “我们分析了 10,000 个工程团队,以下是最佳团队的做法”
- “这三样东西将使速度提高 20%”
如果你能得出一些不太可能的结论,或者提出一些不明显的观点,那就太好了。如果你的观点很明显,那也没关系,但是要强调这一点。例如:
我们都知道吃早餐很重要。但是你可能没有意识到的是,数据告诉我们,它有多重要。吃早餐会让你的寿命延长 20 年。*这是一个如此简单的改变,你知道这很重要,但却有着巨大的影响。
*在这一虚假声明中,没有一份早餐受到损害。
警告:
- 确保您了解收集信息的方法和所有术语的定义
- 了解数据的局限性以及它没有涵盖的内容
- 仔细考虑你的听众以及他们对数据和主题的流利程度。需要有统计学意义的学术水平的数据吗?还是需要一些松散的关联和一点点挥手?你应该坦率地说明你的数据有多可靠,但是根据受众的不同,你会有不同的证明标准。
一般最佳实践
关于学习和知识保留的研究非常明确:你可以做一些简单的事情来帮助你的听众集中注意力,并保留你演讲中的信息。
介绍一下你自己,分享一下为什么你有这些信息,或者为什么你是一个权威。这将建立一些共鸣,并建立与观众的信任。“我做了 20 年的 CTO,领导过 3 - 300 人的团队。”或者“我去年才开始学这个,我学到的一些策略可以帮其他初学者节省很多时间。”或者“我曾在失败的团队和成功的团队中工作过,我想谈谈我的个人经历是如何支持心理安全是团队中最重要的事情这一研究的。我将分享这些数据和一些个人轶事,以帮助您将其带回您的团队。”
使用路标 : 分享议程或演讲大纲,使用视觉提示或设计元素,帮助听众了解你已经讲了多少,还剩下多少。这有助于人们把注意力集中在你的内容上,减少听众的压力。
分享你的学习目标或谈话目标:你的听众应该听什么,你将给他们留下什么?给人们一些提示,让他们知道该听些什么,以及他们会从你的谈话中了解些什么。“在本次演讲结束时,您将有 3 个策略可以在 30 天内降低您的能源账单”“我将用 30 分钟的时间与您讨论如何转向微服务,并分享我们犯下的 7 个错误,您可以避免这些错误。”
以说谢谢来结束你的谈话,然后进入问答环节。不要直接进入问题。为什么?如果直接上 Q+A,一个 Q 都没有,那就尴尬了。给大家一个鼓掌的机会,或者在演示结束时,提问。
练习。你至少需要练习 3 次。三次几乎肯定不够,但这是最低限度。应该怎么练?
- 从自己练习开始。录下你自己的演讲并观看。这可能很痛苦,但是非常有用。
- 请友好的观众倾听。安排一次午餐,与同事一起学习,或者邀请你认识的人参加远程电话练习。这是消除你演讲前紧张情绪的好方法。
- 在你的练习会谈中指定 1-2 个人给你详细的、建设性的反馈。要求非常详细和具体的反馈,达到这样的程度:“幻灯片 1:你没有花足够的时间介绍自己。我得到了你的标题,但不知道你为什么关心这个话题。幻灯片 2 + 3 之间的过渡需要一点工作。不要说,“继续下一点”,“尝试”,而是让我们关注如何使用这种技术来获得结果。”
第五步:发表你的演讲!
你的大日子来了!你能行的。记得慢慢说,但最重要的是,记得当初为什么要这么做。你的目标是什么?试着让自己回到你演讲背后的为什么。激情和情感是每个好故事的核心,无论内容如何。你的演讲和你与材料的个人联系将有助于把你的信息传递给听众,甚至,尤其是当你在演讲时有点紧张的时候。
如果你搞砸了,或者漏掉了一些台词,或者混淆了一个解释,那也没关系。许多人在感觉到他们已经真正掌握了内容之前,会在公开场合做 10 次以上的演讲。
第六步:繁荣!然后重新开始。
祝贺你,你完成了你的演讲!花点时间沉浸在出色完成工作的喜悦中。然后问自己:
- 我还能做得更好吗?
- 下一次我怎样才能说得更清楚呢?
- 我需要感谢谁(组织者、练习伙伴、同事、与会者)的时间、支持和关注?
- 有没有其他的听众可能会对这个感兴趣,或者对这个演讲感兴趣?
- 我能把这个演讲内容用于其他形式吗,比如博客文章?
- 接下来应该提交到哪里?
恭喜你完成了这本史诗般的演讲指南。
如果你想看我们团队过去做过的一些演讲,可以在 YouTube 上看看这个播放列表。
我们是否错过了你最喜欢的建议,或者给出了你认为不好的建议?想要更多关于幻灯片设计、寻找一个好的主题或任何其他与口语相关的技巧吗?让我们知道。
如何在家成功工作:远程工作策略
原文:https://circleci.com/blog/how-to-successfully-work-from-home-strategies-for-remote-work/
对于许多突然面临全新工作环境的员工、团队、家庭和公司来说,远程工作是他们现在最关心的事情。对许多人来说,这是他们第一次在家里长时间工作,同时试图找出如何建立一个新的常态。
除了切换到完全远程设置所涉及的标准挑战之外,许多人还需要应对许多意想不到的变化——孩子们需要在学校关闭时继续学习,宠物突然加入会议,合作伙伴和室友在隔壁房间交谈。我们也担心我们的朋友和家人的安全和健康。有很多事要处理。
CircleCI 的员工相当分散——我们公司大约 40%的员工远程工作,我们的几个团队完全远程工作——但我们仍然每天协同工作,不管在哪里。多年来,我们的许多远程员工提出了许多有用的建议,告诉我们如何作为一名完全远程的员工保持高效和快乐。
这些建议并不是要解决所有在家工作的新的和具有挑战性的问题,但是我们确实认为我们更有经验的同事已经开发的策略可以在我们快速适应这个全新的现实时为我们提供信息。
以下是我们的员工对在家工作的最佳解读:
-
如何在远程团队中沟通:工程师的工具和模板 -沟通很难,在远程团队中沟通更难。幸运的是,它在一个分布式团队中可以和在一个集中的团队中一样有效,如果不是更有效的话。这篇文章深入探讨了我们的团队如何应对远程通信的两个最大挑战:理解语气和支持协作框架。
-
马斯洛的远程工作人员需求层次 -远程工作是一门艺术和科学-它是迭代的,不一定是可以在一夜之间完善的东西。也就是说,有一些重点领域可以帮助你更容易地找到最适合你的工作,这正是客户工程运营分析师 Liene Verzemnieks 在这篇文章中所阐述的。
-
我的分布式团队如何交流,以便不留任何背景信息-circle ci 的许多工程团队大部分或全部是分布式的。由工程团队负责人马雷克·诺瓦克领导的这样一个团队,已经整合了保持团队高效和成功的四个主要技巧:过度沟通、结对/协作、空闲时间使用和会议。这篇文章描述了他们如何学会使用这些技巧作为一个完全分布式的团队茁壮成长。
-
有效远程配对的工具-circle ci 的计划和定价团队 100%远程,几乎 100%的时间进行配对。虽然这看起来像是一个挑战,但该团队已经开发了许多策略,使他们在结对编程中持续成功。在本帖中,我们列出了一些远程配对的最佳技巧,其他首次尝试远程配对的工程团队可能会觉得特别有用。
-
远程优先相对于远程友好意味着什么 -团队可以使用一些工具和策略来让每个人都感到被支持、被联系和被授权——即使是在远处。在这篇文章中,产品经理 Rose Jen 详细介绍了 CircleCI 如何创建一种将远程员工放在第一位的文化。
-
作为一名远程 CircleCI 员工有什么期望 -我们经常在面试中被问到在分布式团队中工作是什么感觉。在本帖中,我们请整个组织的工程师描述他们的经历,并分享一些作为完全远程员工工作的技巧。
如何测试软件:模仿、存根和契约测试
原文:https://circleci.com/blog/how-to-test-software-part-i-mocking-stubbing-and-contract-testing/
使用模仿和存根的测试驱动开发
在如何以及在哪里分离测试环境中,我谈到了构建一个结构化的生产路径:包括哪些测试,何时进行,以及为什么。在这篇文章中,我们将详细讨论如何做每一种测试。
我们将涵盖嘲弄和存根的技术,以及测试驱动开发来帮助每个测试层。首先,让我们回顾一下上一篇文章中的一个概念:测试金字塔。这有助于说明不同种类的测试之间的区别,以及什么时候做这些测试是有利的。
单元或组件测试(显示在我们金字塔的底部)执行起来既便宜又快速。严重依赖这些。只有当你穷尽了这些测试所能做的,你才应该继续进行更昂贵的测试(时间和资源),比如集成测试和 UI 层测试。
在这个系列中,我将介绍每个开发人员工具箱中应该有的各种测试工具,并讨论何时、为什么以及如何使用它们。我将涵盖金字塔各层的测试,以及嘲讽、存根和契约测试的概念。在这个系列的第二篇中,我们将进入测试驱动开发和行为驱动开发(TDD 和 BDD)。
嘲讽和存根是用来做什么的?
很多人认为嘲讽和存根只是用于单元和组件测试。然而,我想向您展示如何在其他测试层中使用模拟对象或存根。
什么是模拟测试?
模仿意味着创建一个外部或内部服务的假版本,它可以代替真正的服务,帮助您的测试更快更可靠地运行。当您的实现与对象的属性交互,而不是与它的功能或行为交互时,可以使用模拟。
什么是存根测试?
存根和模仿一样,意味着创建一个替身,但是存根只是模仿行为,而不是整个对象。当您的实现只与对象的特定行为进行交互时,会用到这一点。
可以在这里找到一篇很棒的博文,它讲述了嘲笑和存根之间的区别。(https://Martin fowler . com/articles/mocksarentstubs . html){:target = " _ blank " rel = " no referrer noo pener " }
让我们讨论一下我们如何应用这些方法来改进我们在上面金字塔的所有层次的测试。
在单元+组件测试中使用模仿和存根
当您的代码使用外部依赖项(如系统调用或访问数据库)时,我建议使用 mock 或 your。例如,无论何时你运行一个测试,你都在练习实现。所以当一个delete
或create
函数发生时,你让它创建一个文件,或者删除一个文件。这项工作效率不高,它创建和删除的数据实际上并没有什么用处。此外,清理费用很高,因为现在每次都必须手动删除一些内容。在这种情况下,嘲讽/打击会有很大帮助。
使用 mocks 和 stubs 来伪造外部功能有助于您创建独立的测试。例如,假设测试将一个文件写入/tmp/test_file.txt,然后被测试的系统删除了它。那么问题就不在于测试不是独立的;那就是系统调用要花很多时间。在这种情况下,您可以存根文件系统调用的响应,这将花费更少的时间,因为它会立即返回。
另一个好处是您可以更容易地重现复杂的场景。例如,测试您可能从文件系统获得的许多错误响应比实际创建条件要容易得多。假设您只想删除损坏的文件。以编程方式编写损坏的文件可能很困难,但是返回与损坏的文件相关联的错误代码只是改变存根返回的内容。
模拟和存根测试示例
def read_and_trim(file_path)
return os.open(file_path).rstrip("\n") #method will call system call to look for the file from the given file path and read the content from them and removing new line terminator.
上面的代码与 Python 内置的 open 函数交互,该函数与一个系统调用交互,以便从给定的文件路径中实际查找文件。这意味着无论何时何地运行该函数的测试:
- 您需要确保测试将寻找的文件存在;当它不存在时,测试失败。
- 测试需要等待系统调用的响应;如果系统调用超时,测试失败。
这两种失败都不意味着您的实现没有完成它的工作。这些测试现在既不是孤立的(因为它们依赖于系统调用的响应),也不是高效的(因为系统调用连接需要时间来传递请求和响应)。
上述实现的测试代码如下所示:
@unittest.mock.patch("builtins.open", new_callable=mock_open, read_data="fake file content\n")
def test_read_and_trim_content(self, mock_object):
self.assertEqual(read_and_trim("/fake/file/path"), "fake file content")
mock_object.assert_called_with("/fake/file/path")
我们使用 Python 模拟补丁来模拟内置的开放调用。这样,我们只是在测试我们实际构建的东西。
在单元测试中使用模拟和存根的另一个好例子是伪造数据库调用。例如,假设您正在测试您的函数是否从数据库中删除了实体。对于第一个测试,您手动创建一个文件,以便有一个被删除。测试通过。但是,第二次,其他人(不是你)不知道他们必须手动创建实体。现在测试失败了。没有要删除的文件,因为他们不知道必须创建实体,所以这不是一个独立的测试。
在这种情况下,您需要防止修改数据或进行操作系统调用来删除文件。这将防止每当有人意外地未能创建测试数据时,测试变得不可靠。
内部函数的模仿和存根
模拟和存根对于单元测试来说非常方便。它们帮助你独立地测试一个功能或实现,同时也允许单元测试保持高效和廉价,正如我们在之前的帖子中所讨论的。
单元/组件测试中 mocks 和 stubs 的一个很好的应用是当您的实现与另一个方法或类交互时。您可以模仿类对象或存根您的实现正在与之交互的方法行为。模仿或阻止其他功能或类,从而只测试您的实现逻辑,是单元测试的主要好处,也是从执行单元测试中获得最大好处的方法。
注意: 你的测试应该和你的代码一起成长。由于单元测试更多地关注于实现细节,而不是特性的整体功能,所以随着时间的推移,它将是变化最大的测试。随之而来的是,当你在测试中使用大量模拟数据时,你的模拟必须以你的代码进化的方式进化。否则,它可能会导致系统中的意外错误。测试不是你写一次就能指望永远有效的东西。当您更改代码并进行重构时,您有责任维护并改进您的测试以与之匹配。
集成测试中的模仿
通过集成测试,您可以测试服务之间的关系。一种方法可能是为测试环境启动并运行所有依赖的服务。但这是不必要的。它会从您无法控制的服务中创建许多潜在的故障点,增加您测试的时间和复杂性。我建议通过使用 mocks 和 stubs 编写一些服务集成测试来缩小范围。我将向您展示这如何使您的测试套件更加可靠。
在集成测试中,规则不同于单元测试。在这里,您应该只测试您有权编辑的实现和功能。模拟和存根可以用于此目的。首先,确定哪些集成是重要的。然后,您可以决定哪些外部或内部服务可以被嘲笑。
假设您的代码与 GitHub API 交互,如下例所示。因为您个人无法改变 GitHub API 如何响应您的请求调用,所以您不必测试它。模仿预期的 GitHub API 响应可以让您更专注于测试内部代码库内的交互。
@unittest.mock.patch('Github')
def test_parsed_content_from_git(self, mocked_git):
expected_decoded_content = "b'# Sample Hello World\n\n> How to run this app\n\n- installation\n\n dependencies\n"
mocked_git.get_repo.return_value = expected_decoded_content
parsed_content = read_parse_from content(repo='my/repo',
file_to_read='README.md')
self.assertEqual(parsed_content['titles'], ['Sample Hello World'])
在上面的测试代码中,read_parse_from_content
方法与解析来自 GitHub API 调用的 JSON 对象的类集成在一起。在这个测试中,我们测试两个类之间的集成。
因为我们在上面的测试中使用了 mock,所以通过避免调用 GitHub API,您的测试将会更快,依赖性也更小。这也将节省时间和精力,因为运行测试的环境不需要互联网接入。然而,为了让您在模拟依赖的外部服务时进行可靠的测试,理解外部依赖在现实世界中的行为是极其重要的。例如,如果上面代码示例中的expected_decoded_content
不是 GitHub 返回回购文件内容的方式,模拟测试中的错误假设会导致意外的破坏。在编写具有模拟响应的测试之前,最好制作外部依赖调用的实际快照,并将其用作模拟响应。一旦用快照创建了模拟响应,就不应该经常改变,因为应用程序编程接口应该总是向后兼容的。然而,定期验证 API 以应对偶尔的意外变化是很重要的。
基于契约的测试中的模拟和存根(在微服务架构中)
当两个不同的服务相互集成时,它们各自都有“期望”,也就是关于它们给出什么和期望得到什么回报的标准。我们可以将这些视为集成端点之间的契约。由于这种标准化,契约测试可以用来测试集成。
让我们看一个例子。正如我提到的,版本标记的 API 不应该经常改变,可能永远不会改变。对于您选择的任何 API,您通常都能找到关于该 API 的文档,以及对它的期望。当您决定使用某个版本的 API 时,您可以依赖该 API 调用的返回。这是提供 API 的工程师和将使用其数据的工程师之间的假定契约。
您也可以使用契约的思想来测试内部服务。当使用微服务架构测试大规模应用时,安装整个系统和基础设施的成本可能会很高。这种应用程序可以从使用契约测试中受益匪浅。在测试金字塔中,契约测试位于单元/组件测试和集成测试层之间,这取决于系统中契约测试的覆盖范围。一些组织利用契约测试来完全取代端到端或功能测试。
基于契约的测试可以涵盖两件重要的事情:
- 检查已达成一致的端点的连通性
- 使用给定的参数检查来自端点的响应
作为一个例子,让我们设想一个天气预报应用程序,它包含一个与用户服务交互的天气服务。当用户服务使用日期(请求)连接到天气服务的端点时,用户服务处理日期数据以获取该日期的天气。这两个服务有一个约定:天气服务将维护用户服务始终可以访问的端点,并以相同的格式提供用户服务请求的有效数据。
现在,让我们看看如何在契约测试中利用模拟和存根。在测试中,您可以创建一个模拟响应,而不是用户服务向天气服务发出实际的请求调用。因为两个服务之间有一个契约,所以端点和响应不应该改变。这将使两个服务在测试过程中不再互相依赖,从而使测试更快、更可靠。
在上一篇文章中,我们谈到了在不同的环境中运行不同的测试,以及有时在不同的环境中用不同的配置运行相同的测试是多么有用。合同测试是后一种情况的一个很好的例子。当在不同的环境中使用不同的配置运行契约测试时,我们可以实现不同的目标。当它是一个较低层的环境时,比如 Dev 或 CI,用一个模拟的契约来运行测试将服务于在环境的约束下测试我们的内部实现的目的。然而,当它进入 QA 或 Staging 等上层环境时,同样的测试可以在没有模拟契约但有实际的外部依赖连接的情况下使用。Mbtest 是一个工具,可以帮助我上面解释的那种契约测试和模拟响应。
我们已经看了使用模拟和存根的不同测试层的例子。现在让我们回顾一下它们为什么有用:
- 使用模拟和存根的测试速度更快,因为您不必连接外部服务。没有等待他们响应的延迟。
- 您可以灵活地确定测试范围,只覆盖您可以控制和更改的部分。对于外部服务,如果他们错了或者测试失败了,你就无能为力了。嘲讽可以确保你把测试范围限定在你能做的范围内——而不是给你自己找不到解决的问题。
- 模拟外部 API 调用有助于您的测试更加可靠
- 契约测试使服务团队在开发中更加自主
在测试驱动开发和行为驱动开发中,我们将探索测试驱动开发(TDD)和行为驱动开发(BDD)的原则,看看它们如何改善从功能测试到单元测试的一切结果。
阅读更多信息:
如何测试软件,第二部分:TDD 和 BDD - CircleCI
原文:https://circleci.com/blog/how-to-test-software-part-ii-tdd-and-bdd/
在我之前的帖子中,我们讨论了 mocks 和 stubs:它们是什么,以及如何在各种测试场景中使用它们来给你自己更多的灵活性,加速你的测试,并从你的测试套件中获得更多的确定性。
在这篇文章中,我将介绍两种从一开始就考虑测试的软件开发方法:测试驱动开发(TDD)和行为驱动开发(BDD)。使用这些方法将会改善你思考软件开发的方式,并且极大地增强你的测试的效率。让我们开始吧:
TDD:测试驱动开发
TDD(测试驱动开发)被认为是一种编写单元测试的方法。在这篇文章中,我们将讨论从功能测试到单元测试的所有事情中使用 TDD 原则。
红绿重构:测试驱动的开发原则
使用 TDD,您可以在实现代码之前设计代码。因此,TDD 迫使你在编写之前考虑组件的行为。这也是让你专注于你想要传递的东西的好方法。在 TDD 中,您为您的方法或实现编写测试,以测试该实现应该做什么。
记住,使用 TDD,你的测试总是先失败。你还没有写代码,所以没有功能。这是好事!它证明你的测试不会只是通过任何旧的实现!
接下来,是时候证明当实现有效并且服务于其目的时,您的测试将通过。一旦您检查到当实现不能正常工作时测试失败,而当实现能够正常工作时测试通过,您就可以重构代码,使之更好、更清晰。因为你已经有了测试,重构会容易得多,而且你可以确信你的测试会告诉你是否成功地改变了代码的行为。这叫做红绿重构。
首先,你让你的测试失败。绿色:然后,让它过去。
先测试,后重构。这确保了你的代码是干净的,可以投入生产。我想强调的是:在你使你的代码变得完美之前,真正经历红色和绿色是很重要的。红色阶段将验证您的测试不只是会一直通过。当事情变得更复杂时,你可以确信它是确定的。后来,在绿色阶段,你的重点不是‘我怎样才能写出最好的代码?’而是‘我如何才能写出满足需求的代码?’将此视为证明您的测试通过有效用例的阶段。在下一个阶段,重构,你将有一个改变,重新审视你的代码。重构阶段是您可以编写更干净、更智能的代码并进行改进的时候。通常,工程师在开始时就开始写作,而忽略了他们应该交付的东西。其他时候,工程师会在创建实现的同时编写测试,并产生意想不到的错误。TDD 有助于避免这些错误。
您编写的测试可能如下所示:
describe('sum()', function () {
it('should return the sum of given numbers', function () {
expect(simpleCalculator.sum(1,2)).to.equal(3);
expect(simpleCalculator.sum(5,5)).to.equal(10);
});
})
1。红色:您的实现当前为空。您还没有实现,所以测试会失败。您希望验证您的测试是确定性的:它会告诉您什么时候应该失败或通过。
var Calculator = function () {
return true // implementation goes here
}
2。绿色:实施。让测试通过。这里我们将编写通过测试的代码。
var Calculator = function () {
return{
sum: function(number1, number2){
return number1 + number2;
}
};
}
现在您的测试将会满意,因为我们已经添加了函数。
重构代码:现在,重构你的代码,使之更清晰,可读性更强。前两步使您的测试可靠,并且您不必担心意外修改代码的行为。请记住,您通过经过红色和绿色阶段的测试验证了代码的功能。因此,一旦代码处于重构阶段,测试就不应该改变。如果您现在进行更改,您会增加源代码中出现功能故障的可能性。如果您需要更改测试,请确保在红/绿阶段进行更改。
一旦你有了一个有效的测试,你就可以重构代码,使之更清晰,更符合风格或整个类。
把所有的放在一起
上面的例子是一个单元测试。但是我们如何在测试金字塔的其他层上使用 TDD 呢(关于这个金字塔的深入解释,参见我之前关于测试的帖子)?
当我进行实现时,我将首先从 UI 层测试开始(使用 BDD,我将在下一节解释)。尽管这些 UI 测试在很长一段时间内都不会通过,但从测试开始有助于我专注于我实际尝试构建的东西,以及我的后端代码将如何与前端层交互。这种方法允许开发人员在编写实现之前设计实现。
从那里,我开始从事单元/组件测试或集成测试,这取决于工作本身。如果在我深入研究代码库之前,架构设计是清晰的,我就开始编写集成测试。这些也会失败一段时间。虽然在我写它们的时候,它们可能还不完整,但它们仍然有助于我思考我试图构建的东西和我最初的设计是什么。
当我转移到单元/组件测试时,我最终在单元测试层开始红绿重构,将 UI 和集成层留在“红色”阶段,并将我的单元测试完成到重构阶段。然后我回到集成测试,将文本变成绿色,然后重构。之后,同样的步骤适用于 UI 测试
正如你所看到的,我在测试的所有层面都应用了 TDD 原则。原理是一样的,唯一不同的是尺度。
BDD:行为驱动开发
用户旅程故事和给定的时间和地点
每当有新的特性请求时,来自业务产品方面的人员为工程师编写故事级任务,包括用户故事和用户接受标准。这样,作为一名工程师,您可以理解业务的价值,并从用户的角度考虑他们将要实现的功能。通过查看用户故事,工程师也可以更好地理解工作的范围。
用户接受测试(UI 驱动测试)建立在用户接受标准和用户故事的基础上。UI 驱动测试通常使用类似于 Selenium 或cumber的工具,这些工具可以帮助测试用户在一个已经启动并运行的网站上的旅程。
用户旅程故事代表了用户的行为。使用所提供的业务需求,开发人员可以考虑用户将如何使用这一新功能的场景。这些场景可以用来编写测试。这被称为行为驱动开发(BDD)。
BDD 是 UI 驱动测试中广泛使用的方法。它是以一种被称为“给定,何时,然后”的结构编写的。
给定- 系统的状态,当- 该行为/动作发生并最终导致结果
然后- 该结果由行为状态中的行为引起
首先考虑用户的旅程和用户的行为是一个好主意,这样当你实现你的特性时,就可以考虑用户将如何与之交互。例如:
场景:用户登录网站。
假设用户访问了网站
当用户点击注册按钮
然后确保用户可以访问注册页面
下面是一些用 Cypress 的简单测试代码示例(为了便于与这个工具集成,探索一下 Cypress orb ):
describe('User can signup to the test-example site', function() {
it('clicking "signup" navigate to a signup url', function() {
// Given
cy.visit('https://test-example.com/')
// When
cy.contains('signup').click()
//Then
cy.url().should('include', '/signup')
})
})
在 UI 层测试中使用 BDD 是有意义的,因为它涉及到用户将与之交互的应用程序部分。其他层次的测试不太适合使用 BDD。虽然使用 BDD 的 UI 层测试对于构建高质量软件的过程来说是无价的,但是它非常昂贵且低效(参见本博客系列第一部分中的测试金字塔)。
正如我们在上一篇文章中提到的,利用不同的层和不同种类的测试意味着当出现问题时,可以更快地准确定位出问题所在,并能够更快地修复它。这减少了调试时间,并使您能够更便宜、更快速地检测低级别的问题。
结论:快乐之路和边缘案例
当您编写测试时,很容易想到当一切顺利时会发生什么。对于工程师来说,考虑边缘情况可能是一个挑战。这是意料之中的。
当我们考虑 UI 层测试时,我们假设(几乎)整个站点已经启动并运行,并且您的测试正在运行。现在,很难想象用户可能采取的每一条途径,并且测试可能出现的每一条途径是非常昂贵的。因此,关注快乐的路径和主要的失败路径是一个好的实践:这些将涵盖主要的行为和最坏的情况。边缘案例错误通常是在类似 QA 的环境中通过 QA 探索性测试发现的。在这个过程中,QA 将分析业务风险,并将边缘情况场景传达给工程师,以确保他们在代码投入生产之前修复错误,并编写新的测试来覆盖边缘情况场景。
当工程师更好地理解系统和环境时,就更容易考虑边缘情况。这导致边缘案例中的测试被测试金字塔的较低层更好地覆盖——这总是更好的,因为它们更有效。也就是说,维护测试也是工程师工作的一部分。当您的代码发展时,您的测试也需要改变。拥有有意义的和行为驱动的测试比你拥有的测试数量更重要。毕竟,测试的目的是向产品交付高质量的软件。
让你的代码库更具可测试性是一项值得的投资,从长远来看,它将帮助你扩展你的业务和软件。这项基础工作将允许您优化软件的生产路径,让您每次部署时更有信心。
Orb 设计最佳实践| CircleCI
原文:https://circleci.com/blog/how-to-write-an-orb-that-people-will-love-to-use/
自从我们推出 CircleCI 的 orbs 以来,已经有将近一年的时间了,这是世界上第一个专门为软件交付自动化的配置而设计的包管理器。 Orbs 使 CI/CD 工程师能够简化他们的配置并消除某些任务的重复。现在,任何人都可以使用社区开发的解决方案来下载 CLI、集成测试、添加安全检查或部署到生产环境中。在过去的一年中,我们有机会看到我们的用户是如何利用 orb 的,有了这些知识,我们能够确定设计策略来创建有用的、可重用的和可参数化的 orb,任何人都可以使用。
下面的资源列表将帮助您创建一个使用率最高的 orb。
摘要
最好的 orb 作者也是一个伟大的 CircleCI 配置作者。有许多方法可以编写 orb,但是与任何编程或脚本语言一样,您对语言的基本原理了解得越多,您的代码就越好。当设计一个 orb 时,总是要考虑最终用户的立场和需求。orb 的目的是尽可能减少开发人员和他们试图使用的服务之间的摩擦。有了这个指导原则和上面列出的资源,你就可以创建一个为你和更广泛的社区提供价值的 orb 了。
防止 CircleCI | CircleCI 上的密码挖掘
原文:https://circleci.com/blog/how-we-find-block-and-prevent-cryptomining-at-circleci/
安全是我们业务的核心。
每天,客户都信任我们能够访问他们的源代码和其他秘密。我们通过在系统开发生命周期的每个阶段将安全性融入我们的平台来努力赢得这种信任,从设计阶段就包括安全工程师,一直到我们生产系统的季度第三方审计。我们的辛勤工作使 CircleCI 的客户能够安全可靠地开发出令人惊叹的产品。因此,防止这种情况发生的任何事情都是我们最关心的问题。大多数时候,这项工作是确保我们安全地构建我们的软件,这样我们也可以安全地构建您的软件。然而,有时我们努力防止人们以损害我们客户的方式滥用我们的平台。
这包括那些为了挖掘加密货币而利用我们免费计划的人。
滥用 CI 挖掘加密货币
正如在我们的领域中常见的那样,我们向客户提供免费计划,让他们有机会评估我们的平台。我们还向开源社区提供免费计算。然而,我们的行业已经看到越来越多的参与者使用像这样的免费计划来挖掘加密货币,而不是开发软件。挖掘加密货币的机制各不相同,但它们通常都涉及到用一些价值来换取矿工提供的工作证明。在这种情况下,他们使用我们为开源社区提供的资源,而不是使用它们来完成他们获得报酬的工作。
智胜密码矿工
我们的平台受到由安全专家、运营工程师、数据科学家和开发人员组成的跨职能团队的保护,他们的持续工作包括发现和根除对我们平台的滥用。这包括违反我们的服务条款的任何使用我们平台的行为,包括挖掘加密货币。通过复杂的分析,我们发现了使用我们平台挖掘加密货币的组织,并从一开始就阻止了被认为可能是加密矿工的组织注册。
今年到目前为止,我们已经禁止了超过 80,000 名滥用我们平台的用户,随着我们检测方法的改进,我们预计我们平台的滥用将继续下降。我们还与竞争情报领域的其他公司密切合作,分享已知滥用组织的详细信息,以及它们的攻击技术和我们如何检测它们。通过不断地相互学习,我们不断地增加我们可用的工具集,以根除对我们平台的滥用。
谢谢你保护 CircleCI 的安全
感谢所有在我们平台上报道过密码挖掘可能性的人!我们意识到了这一点,并对我们的实施充满信心。此外,我们希望听到您可能发现的任何其他安全漏洞——给我们发电子邮件至 security@circleci.com。
加入我们的团队
从事这项工作听起来是不是很棒?如果是这样,我们有一个高级威胁检测工程师的空缺给一个了不起的人,他将全职从事这项工作。其他空缺职位,请参见我们的招聘页面。
我们如何更快地雇佣更多的工程师
原文:https://circleci.com/blog/how-we-hired-more-engineers-faster/
大约一年前,我们的工程组织意识到它有一个问题。CircleCI 正处于高速增长模式,需要雇佣更多的工程师…我们需要尽快完成这项工作。但是我们目前的流程耗时太长。我们知道流程可以改进,我们只需要找出改进的方法。
因此,正如我们在 CircleCI 经常做的那样,我们开始实验。我们优先安排更多的时间进行面试,我们尝试将技术面试外包给第三方,我们为候选人尝试了新的不同类型的问题。当我们仍然不能足够快地找到合适的人才时,我们一次又一次地重复我们的过程。
在一年内进行了 6000 多次工程面试后,这是我学到的寻找顶级工程人才的最佳方式,以及如何为一家快速增长的公司扩展这一流程。
腾出更多的时间进行面试
我们发现的第一个问题是我们的采访过程太长了。我们失去了最优秀的候选人,因为他们等不及几个星期来完成面试。我们想出的最初解决方案是重新安排一些内部会议,以便腾出更多时间进行采访。这让我们可以更快地通过候选人,但负面影响是耗尽了我们内部团队的所有时间和精力。
这是我们第一次决定尝试将技术采访外包给第三方。这减轻了我们内部团队的压力,因为候选人可以在白天或晚上的任何时间安排面试,而第三方公司拥有准确评估候选人的技术知识。尽管如此,我们的团队不得不观看每一次录制的采访,看看他们是否同意这一评估。也很难修改或重复采访过程,因为我们不拥有整个事情。重要的是,一些候选人不喜欢我们在技术面试部分使用第三方,并因此退出竞选。
使用第三方来支持招聘,但不要外包整个过程
很明显,我们需要拥有更多的面试过程,这样我们就可以控制问题、练习和评估,但我们没有带宽来自己运行整个过程。
那时我们决定将我们的技术筛选转移到一个名为 CoderPad 的平台上。CoderPad 并不为我们做技术面试,他们只是为候选人提供一个与我们在代码上配对的环境。我们仍然自己设计问题和进行采访,这使我们能够随着我们了解什么是有效的和我们的扩展来发展这个过程。
设计一些问题,给你想要的那个角色的信号
对于某些角色,这需要 5 分钟;对于其他角色,我会花几个小时在这上面。你做得越多,想出的能发出好信号的深思熟虑的问题,结果就越好。当我面试的时候,我不会亲自审查编码技能。我通常审查更高层次的技能,比如与团队合作、管理组织或激励他人的能力。
我通常会问这样的问题:
- 你想从一个新角色身上得到什么,而你今天却没有得到?
- 你如何衡量[他们申请的任何职位]的成功?
有时我会说得更具体,但通常情况下,最好保持对话的高层次。我还对申请相同职位的所有候选人使用相同的问题,以帮助减少偏见,确保公平竞争。
学习如何在面试中避免偏见,鼓励应聘者为自己辩护
不要问抽象的问题。询问做这项工作所需的技能。
对于一些角色,我们描述了一个场景,在这个场景中,一个系统出现了操作故障,让候选人带我们进行故障排除和调试。对于其他人,我们可能会让他们基于新的流量或负载量来增强系统。我们会询问你在工作中需要具备哪些能力,因为这能更好地反映这个人解决问题的能力。
我经常会问这样的问题:“在你的职业生涯中,你最自豪的是什么,或者你创造了什么?”这个问题通常出现在面试的早期,以建立融洽的关系,让候选人积极地谈论一些事情。有时我会问一些更开放的问题,比如“构建、操作或验证分布式系统有什么困难?”这些问题经常在经验层面上给我很多信号。
文化不是想和某人一起出去玩;这是关于工作方式的
这个人可以在户外工作吗?他们能通过影响力吸引其他人吗?即使不是他们最喜欢的东西,他们也能传递信息吗?相对于局部优化,他们能进行全局优化吗?我问这些问题是为了发现一个候选人是否是一个好的文化适应者。文化契合并不是说你想和那个人交往,而是说他们有和你团队兼容的工作风格。
我问的大多数问题都以“告诉我一次”或“举一个你……”的例子开始,我想知道细节。如果我采访你,我想知道你是否做了好事,或者站在做了好事的人旁边。与此同时,你是把所有的功劳都揽在自己身上,还是谈论一个团队的成功?当你失败时,是别人的错还是你自己的错误或问题?
寻找好奇的人
在 CircleCI,我们需要好奇的工程师。如果你在一层之后停止寻找答案,你可能真的不明白发生了什么或为什么。例如,在停机期间,如果您发现系统因为数据库连接耗尽而停止运行,那么您还没有修复任何东西。您可以创建更多的连接或重新启动数据库,但您知道为什么它没有连接吗?是因为长时间运行的查询吗?连接池算法坏了吗?当我们结束了这些联系,我们不是在关闭它们吗?我们是不是增加了什么东西的超时时间?
停机的原因可能有很多。让我们找出是哪一个。很多人谈论寻找“根本原因”,但我认为这是一个有问题的标签,因为它经常鼓励人们停止寻找。总会有更深的一层需要探究。这些就是我要找的工程师。
面试不是战斗
请记住,你不是在那里试图显示你比候选人知道的更多,或者看看他们在哪里跌倒。你在那里是为了看看他们是否能做这项工作,以及你是否能和他们一起工作。帮助候选人不是欺骗…你一直在工作环境中帮助你的同事。所以,回到候选人是否具备该角色所需的基础知识。同样,你能和这个人一起工作吗?
面试是有压力的,所以不管怎样,你都应该确保每个应聘者都有一次很棒的经历。如果他们没有得到这份工作,你希望他们认为“该死,我想在那里工作。那个地方看起来棒极了。”也许他们会在更好的情况下再次申请,也许他们会推荐其他人。最后,他们把自己放在了那里,所以让我们认识到这一点,并尊重地交付整个过程。
我们如何改进 CircleCI:成长工程团队的经验
原文:https://circleci.com/blog/how-we-improve-circleci-learnings-from-the-growth-engineering-team/
在 CircleCI 的增长工程团队中,我们定期进行或大或小、或复杂或简单的 UI 实验。每一个都揭示了更多关于我们的客户如何以及何时使用 CircleCI,以及我们如何让他们的体验更好。
我们的团队在设计这些实验时遵循三个价值观:增量、好奇心和为用户增加真正的价值。
以下是这些价值观如何变成实验的例子,以及我们从每个实验中学到了什么。
增量:UX 的小烦恼产生大影响
当新的成长工程师加入我们的团队时,我们要求他们在 CircleCI 上建立一个项目,并写下他们所有的困惑或沮丧之处。
一名工程师指出,当他将鼠标悬停在解释工作页面上的并行度的工具提示上时,过了几秒钟才弹出:
我们的团队构建了原始的工具提示作为不同测试的一部分,但是因为我们优先考虑小的、增量的改进,我们当时使用了开箱即用的浏览器功能(以获得更快的反馈),而不是构建我们自己的适当工具提示组件。从这个实验中,我们发现向用户提供更多关于并行性的信息会导致更多的组织提升他们的并行性水平。
如果我们构建一个更好的工具提示,我们会看到更多的并行使用吗?
我们运行了一个 A/B 测试,将浏览器的原生工具提示(我们用作黑客)转换成一个真正的、定制的工具提示,它会立即弹出:
我们再次观察到,与对照组相比,处理组(使用新的工具提示)的组织利用并行性有了显著的提高(从 12.5%提高到 14.9,p=0.00,没有比这更显著的统计数字了!)
这是一个很小的 UX 调整,以至于我们最初争论是否要进行测试。我们认为它不会改变什么,但它确实显示了一个重要的提升。
通过增量,我们可以更多地了解用户如何与工作页面交互。我们还了解到一个更广泛的事实:UX 的小改进会产生很大的不同。
好奇心:了解用户正在尝试做什么,并帮助他们更快地完成
随着时间的推移,我们发现一些帮助用户提高效率的尝试并不奏效。例如,我们开展了一项我们认为非常有吸引力的教育活动,向用户展示他们可以通过更频繁地运行较小的提交来更快地从失败的管道中恢复。
令我们惊讶的是,看了广告的治疗组比没看广告的治疗组平均少跑了几条管道。
我们很好奇这些结果是否与我们试图改变用户现有的工作流程,而不是加速他们当前的工作流程有关。如果我们在用户的现有流程中运行不同的实验,结果可能会有所改善。
我们了解到,大多数用户希望重新运行管道,他们只是不想为此进行多次额外的点击。我们新的 A/B 实验显示了顶层仪表板上的“重新运行管道”按钮——用户最常与之交互的页面。这不是一个新功能,但是我们想知道把按钮放在更中心的位置是否会促使用户更频繁地重新运行管道。
我们的直觉是正确的——这一变化导致管道重新运行的比率更高。
我们还发现,通过将重新运行按钮放在一个中心位置,更多的组织可以看到重新运行是一个选项,并且有大量新组织第一次开始使用该功能。
这两个结果之间的对比表明,将我们的实验与用户当前的工作流程相结合比试图让他们做一些新的或不同的事情更有效。这是一个我们通过更多的实验反复证实的结论。
增加价值:减少“快乐的时间”
我们从数据和 UX 研究会议中了解到,一些新用户需要很长时间来设置。这导致他们没有充分利用可用的工程资源来优化他们的管道,或者在某些情况下,完全离开平台。
根据我们开发者关系团队的意见,我们决定尝试在 UI 的右侧面板添加一个“入门”清单。该清单包括鼓舞士气的项目,如“运行您的第一条管道”和“运行您的第一个绿色工作流程”,以及阅读更多关于配置 CircleCI 的高级文档。
这里的目标是减少用户体验 CircleCI 全部价值的时间——或者我们喜欢称之为“减少快乐的时间”。
该实验使组织在加入该平台三周内的参与度提高了 27%。
我们了解到,减少快乐的时间对我们的用户有真正的影响。如果我们能够加快他们的入职速度,并帮助他们在这一过程中减少气馁,他们就可以更快地开始工作,这将为他们、他们的团队以及他们更大的组织增加真正的价值。
这才是真正的意义所在:我们进行这些参与实验,以了解如何让 CircleCI 更好地为我们的用户服务。随着我们继续运行测试,我们继续了解我们的用户需要什么来使他们更有生产力、更成功和更快乐。
你喜欢这些价值观的声音吗?你有兴趣做这种很酷的实验吗?我们团队在招人!查看 CircleCI 成长团队的最新空缺职位。
我们如何面试 CircleCI 的工程师
原文:https://circleci.com/blog/how-we-interview-engineers-at-circleci/
来自出版商的说明:截至 2020 年 9 月,我们关于工程招聘流程的最新信息可以在这里找到。
自 2018 年初以来,我们已经有超过 1000 名候选人通过了工程招聘流程。我们的工程面试由初步筛选后的四个阶段组成。我们分析了通过招聘流程各个阶段的候选人比例,结果如下。
从任何一组 1000 名申请者中:
250 会通过初筛。117 将通过招聘经理的电话筛选。
44 人将通过面试的微观技能评估部分。
7 将通过宏观技能考核。
不到 3 人将通过现场面试并获得聘用。
在我们的系列 C 之后,我们在目前所学的基础上进一步加大了招聘力度。我们最近在内部讨论了很多关于我们如何面试的问题,我想人们可能会对工程师职位的面试流程感兴趣,为什么。
反思技术面试
关于软件行业的面试实践已经说了很多。我们已经看到或听到了这一切:从不透明的设计到彻头彻尾的奇怪(我曾经被遗弃在一个会议室,独自一人,只有一个午餐袋,不知道接下来会发生什么)。
没有人喜欢这种类型的面试。指导他们的人不知道,候选人也不知道。毕竟,如果没有一个旨在施压、迷惑或恐吓的过程,求职面试就已经够紧张的了。
我们面试候选人的唯一目标是:
- 确定最佳候选人,并邀请他们加入我们的公司。
- 为所有候选人提供积极的体验。
自从我加入 CircleCI 以来,我们一直在努力设计一个我们希望自己经历的面试流程,一个在帮助我们找到团队最佳补充的同时向候选人表示尊重的流程。
面试结构
我们设计了一个 4 步技术面试,遵循所有候选人通过的初始筛选。我们所有的面试都遵循相同的顺序,每个阶段都是为了完成特定的评估:
1。手机屏幕。该职位的招聘经理将与候选人交谈,评估其经验、沟通能力以及在生产中处理自己代码的经验。
2。微技能带回家的问题。候选人完成一个编码问题,与面试官一起回顾。与候选人讨论问题有助于我们评估候选人的能力和思维过程,以及他们在编写软件时的优先事项和价值观如何与我们保持一致。我们知道的许多公司对于经理角色跳过这个阶段,因为他们不会写很多代码。我们将它包括在内,因为发现候选人的价值观和优先事项是否与他们将管理的团队的价值观和优先事项一致非常重要。
3。宏观技能设计问题。与工程团队高级成员的对话重点关注候选人在面对日益复杂的需求时如何设计和改进解决方案。答案没有对错之分,而是作为一个沙盒,让我们看到他们能力的界限在哪里。我们对这次测试的评分将取决于他们所面试职位的级别。
4。现场面试。现场面试的目标是让双方确定候选人应该是 CircleCI 团队的一员。候选人与工程团队成员配对,在实际的 CircleCI 代码库中一起解决问题/项目。这让我们的团队和候选人都体验了一起工作的感觉,并让我们了解这个人在更复杂的互动过程中是如何处理问题、合作和沟通的。在配对结束时,双方都应该觉得能够对合适与否做出自信的决定。更新,2019 年 3 月: 我们现在已经转向完全远程的采访流程,以反映我们实际的日常合作。我们仍然使用这个面试阶段,但是所有的面试都是远程进行的。
创建尊重他人的流程
我们写了一份内部招聘指南,涵盖了我们在面试时试图坚持的价值观,我在下面分享了一些。对候选人表示尊重对我们来说非常重要,这可以通过多种方式表达出来。我考虑这些基本的礼节:当候选人到达时,有人迎接他们,或者不要让他们独自一人,想知道接下来会发生什么。我们的一些面试指南是:
善良。面试压力很大,大多数公司都让候选人经受荒谬的考验,这只会让情况变得更糟。让我们举一个例子来说明事情可以变得更好。
考真本事。我们是专门反对“白板面试”的。我们要求自己,在任何情况下,都不要将候选人置于不代表他们正在面试的职位的日常现实的情况中。在白板上讨论设计方案是好的,但期望候选人背诵复杂的算法就不好了。
尊重考生的时间。我们准时开始和结束面试,目标是在 24-48 小时内给候选人反馈。
做你的家庭作业。不要让求职者回顾他们的工作经历。相反,在你面试之前先看看候选人的简历,准备好讨论有趣或相关的经历。
把大部分时间花在倾听上。如果你说话的时间超过了 20%,你就没有尽可能多地从候选人身上学到东西。
明智地使用词语
这要从职位描述说起。我们尽最大努力避免“兄弟文化”或其他带有高度偏见的语言。在我们所有的写作中,包括工作描述,我们努力使用强调合作、信任和学习的包容性语言。
如果你想知道你的职位描述是否传达了你不想传达的信息,Joblint 和 T2 性别解码器是两个很好的工具来解析有偏见的语言。
例如,这是我们通过性别解码器招聘高级后端工程师的广告:
我们在工程职位描述中有意使用中性和女性化的语言,以创建更具包容性的招聘流程。研究表明,女性不太可能对过于男性化或带有攻击性语言的广告做出反应(尽管有资格),而男性不管怎样都会申请。
持续学习
这一进程将继续发展,并借鉴我们的经验。例如,目前申请人的平均转换率为 0.5%,我们需要查看多达 4000 名候选人才能再雇佣 20 名工程师。
我们的最终目标是让最好的人在这里,做他们最好的工作。随着我们不断学习和完善,我们希望在保持高标准的能力和候选人经验质量的同时,提高我们的转化率。
我们的受访者对这一过程的反馈总体上是积极的,我们在完善我们的采访过程中始终欢迎各种反馈。如果您已经完成了我们的流程并有反馈,我很乐意收到您的来信。给我发邮件到 jeff@circleci.com。
如果你有兴趣申请这里的工作,我们也很乐意和你谈谈!在这里看看我们开放的角色。
有兴趣了解更多在这里工作的情况吗?阅读:
招聘软件工程师-偏见缓解-全球分布式公司| CircleCI
原文:https://circleci.com/blog/how-we-interview-software-engineers-what-we-ve-learned-what-we-ve-changed/
在过去的一年里,我们有超过 5000 名候选人通过了工程招聘流程。
这相当于 5000 次招聘筛选、近 1000 次面试、177 次最终面试和 63 份工作邀请。
这是 5000 次问自己如何继续改进招聘流程的机会。
自从我们两年前写了关于如何在 CircleCI 面试工程师的文章后,我们又筹集了两轮资金,工程团队的规模几乎扩大了两倍。为了跟上我们不断增长的组织,我们还需要更新我们的招聘流程,以更好地适应我们当前的需求。
这篇文章将涵盖新的结构,这些结构背后的原因,以及我们目前在 CircleCI 招聘工程师的面试流程的详细概述。
什么没变
我们仍然不相信白板面试或其他面试做法,这些做法在我们的行业中仍然很常见,主要是为了让候选人失败。我们面试候选人的主要目标是:
- 确定最佳候选人,并邀请他们加入我们的公司。
- 为所有候选人提供积极的体验。
为了实现这些目标,我们依靠一致性和结构。我们使用标准化问题的结构化面试流程。我们还设计我们所有的角色和工作描述,并根据我们的工程能力矩阵评估候选人。
去年,我们为所有面试官引入了面试官培训。我们的面试官培训由自我指导培训和面试跟踪组成。自学式培训涵盖的领域包括:我们的招聘流程和面试官在其中的角色、认知偏差以及如何减轻这些偏差、面试的法律方面、对我们的申请人跟踪系统(ATS)的介绍、如何准备、进行和结束面试,以及如何评估候选人。当面试官需要针对特定面试进行额外培训时,我们也会使用模拟面试环节。到目前为止,回应非常积极,每个人在如何有效地进行采访方面的一致也帮助我们提高了组织水平。
持续学习
我们公司价值观之一是“快速和持续”:
我们重视快速迭代和发布,然后精炼和调整,而不是试图一次完成所有事情。我们选择快速实验,把事情做好,并不断学习。
不断学习和发展是我们工作的核心:这是我们产品的核心,也是我们作为一个组织如何运作的核心。我们不断投资改进我们生产的产品,以及我们作为一个团队的工作方式。改善我们的招聘方式是其中重要的一部分。
回应候选人的反馈
我们会询问每一位与我们一起面试的候选人对他们经历的反馈。多年来,许多人与我们分享了他们的想法。我们会查看收到的每份反馈调查回复,并与我们的团队一起调整招聘流程,以解决这些反馈意见。
他们指出了我们做得很好的领域:我们的团队中有许多优秀的人,他们乐于谈论他们的工作并回答候选人的问题;我们还听说候选人喜欢我们面试关注的不同角度,以及与我们招聘团队的互动。
我们还听说了我们可以改进的地方:确保与候选人保持密切的沟通,以及在流程的早期澄清角色和职责。
一个反复出现的反馈是我们流程的长度:候选人认为它是彻底的,但感觉它相当长。在这个过程中,我们也失去了一些优秀的候选人,因为他们在我们完成面试之前就收到了其他地方的邀请。我们知道我们需要创建一个更加简化的流程,仍然可以为一个全球分布的团队工作,具有许多时区,并保持我们的标准进行彻底的采访。这是我们现在使用的流程。
更新的面试结构
高级工程职位的面试结构
自 2019 年 3 月以来,我们的面试过程一直是完全远程的,面试通常通过视频会议软件进行。截至 2020 年 8 月,我们的面试结构包括以下几个阶段:
1。招聘人员会议:我们的技术招聘人员与候选人会面,讨论他们申请的职位、他们的职业兴趣以及他们对下一份工作的期望。我们收到了许多候选人的来信,他们非常喜欢与我们的招聘团队互动——他们帮助我们的候选人获得了顺利的体验,每天都非常努力地工作,以更好地了解候选人,并找到最适合这份工作的人。
2。招聘经理筛选:该职位的招聘经理与候选人交谈,评估与该职位相关的经验、沟通和协作技能以及来自我们能力矩阵的其他核心技能,以及处理该职位特定职责的能力。
3。技术面试:各个层次的工程候选人都要参加与两位工程师的结对编程面试,并在多种语言(Clojure、Javascript、Go、Python、Java、Ruby)中进行选择进行面试。这个面试的目的是看工程师如何交流,解决问题,读代码,写代码。面试的目的是模拟工程师在平常的日子里如何一起工作。除了结对编程面试之外,员工级别及以上的角色将与工程团队的高级成员进行对话,重点讨论候选人在面对日益复杂的需求时如何设计和改进解决方案。答案没有对错之分,而是作为一个沙盒,让我们看到他们能力的界限在哪里。我们如何给这个测试打分将取决于他们面试的职位的级别。
4。团队面试:这个阶段是与候选人申请加入的团队中的两名成员进行对话。这次会议我们有三个目标。我们想了解候选人具备哪些技术技能。我们希望评估沟通、协作和用户价值交付方面的技能。最后,我们想确定我们是否认为他们能够胜任这一角色。我们一直在努力扩大我们在团队中代表的观点、背景和经验的数量。
5。领导力问答:每次面试都有时间让候选人向我们提问,有时上次面试后会留下一些问题,因此,根据要求,我们会提供一次与招聘经理或该职位领域的高级工程经理的选择性总结谈话。对于某些角色,总结对话默认是招聘流程的一部分。
如果你对面试过程或阶段有任何疑问,请随时向招聘经理或招聘人员询问你申请的职位。我们理解面试可能是一次充满压力的经历,我们希望尽最大努力让您在这个过程中感到轻松。
提供积极的候选人体验
我们所有面试官都经历的面试官培训的一大部分是如何提供积极的候选人体验:我们希望为每个候选人提供良好的体验,并希望对我们的公司和面试过程留下持久的积极印象——无论我们是否向他们提供机会。所有我们信任的面试官都在为我们的候选人提供这种体验方面发挥着重要作用。面试压力很大,一些公司让应聘者经历一次又一次的考验,这只会让面试变得更糟。(显然,白板面试似乎仍然存在)。我们想成为事情如何变得更好的榜样。虽然面试官可能会和很多人交谈,但对许多求职者来说,这是他们唯一一次和我们交谈,我们都想留下一个积极的印象。
具体来说,我们会向面试官提出以下问题:
- 时刻准备着(我们对此有详细的说明),时刻准时出现
- 如果你不确定如何读候选人的名字,就去问(并留个便条给其他面试官看)。
- 听好了,不要插嘴。记住这是给他们一个机会去分享他们有多棒;让对话集中在候选人和他们的经历上。
- 与候选人保持远程联系可能会很困难,这种远程联系会加剧性格差异。请注意,仅仅因为你在与候选人交谈时没有“点击”他们,并不意味着他们不合格。
- 如遇技术困难或其他问题,请耐心等待。
我们感谢每一位决定与我们面试的候选人,并希望确保这种感谢在我们的实践中得到体现。
继续改进我们的实践
我们将继续改进这一流程,因为我们会更多地使用它,并听取我们内部面试团队以及候选人的反馈。几名候选人已经在过去几周内完成了我们修改后的流程,并与我们分享了他们的反馈——谢谢!您的反馈有助于我们进一步完善这一点,我们非常感谢您抽出时间来帮助我们改进。如果您已经了解了我们的招聘流程并有反馈意见,请在候选人调查中与我们分享,我们希望听到您的反馈。
如果你有兴趣加入我们的团队,请在我们的职位页面上找到更多关于我们和我们的空缺职位的信息。
作为一个全球团队,我们如何坚持我们的包容性价值观- CircleCI
原文:https://circleci.com/blog/how-we-uphold-our-inclusive-values-distributed-team/
分散经营的好处
从早期开始,CircleCI 就有意打造一支全球化的员工队伍。这个简单的选择给了我们很多好处。首先,我们可以接触到地球上最优秀的人才。我们可以接触到的各种各样的观点有助于我们做出更好的决策。同样重要的是:它让我们能够一天 24 小时不间断地为客户提供价值。作为一家公司,团队成员遍布全球为我们带来了许多优势。
然而,更有价值的是,我们知道远程工作的灵活性也为我们的全球员工带来了相当大的好处。我们问他们喜欢远程工作的什么,以下是他们最喜欢的一些福利:
- 完美的办公室。你可以选择(或构建)你理想的工作环境:是意味着更安静、更少的社交干扰,还是窗外鸟儿歌唱的声音,以及你的狗在你脚边安静地打呼噜的轻微隆隆声。
- 没有浪费时间。你可以用拥挤的火车上的长时间通勤来换取更多与朋友、家人或喜爱的爱好共度的自由时光。
- 无限的灵活性。根据需要调整时间表,减轻平衡家庭和工作的压力。
我们是如何做到的
CircleCI 公司由 111 人组成(并且还在增长!),其中 36 个是远程的,占公司的三分之一!我们的一些团队比其他团队拥有更大的远程组件,这取决于他们所做的工作类型,以及哪种类型的设置可以让我们更好地满足客户需求。有些团队,比如工程团队,天生适合异步工作,因为他们可以从 Slack 和 Github 等共享资源中获取所需的上下文,然后埋头单干。其他团队,如营销和销售团队,主要在同一时间同一地点工作会受益;例如,能够在销售电话后与队友分享实时反馈可以帮助团队成员更快地迭代和改进他们的过程。
我们从一开始就是一个分散的团队;异步运行是我们的天性。由于这一历史,自从我们成为一家公司以来,我们围绕位置无关协作的许多实践就一直伴随着我们。我们一直努力确保随着我们的成长,我们能够成为一个包容所有人的工作场所,无论工作地点在哪里。
“这是我的第二份远程工作,CircleCI 带给我的两个最大的不同是我们得到的信任和每个人合理关心的程度。远程工作的能力是一回事,但 CircleCI 给了我远程发展的机会。真的很棒。”-Ryan O'Hara,科罗拉多州高级客户成功工程师
我们是如何做到的?从一开始,我们就接受了沟通实践,确保人们不必亲临现场就能了解情况。这渗透到每一件事,从投资坚实的影音到我们作为一个团队计划和执行任务的方式。
投资支持以下功能的系统
以下是我们在支持分布式工作人员方面取得的一些成效:
- 创造信任的文化。“这并不局限于远程工作,但是如果没有一个广泛的理解,即每个人都值得信任来完成他们的工作,健康的远程工作是不可能的。如果有哪怕一丁点儿的想法认为远程工作人员没有办公室工作人员努力,那么有效的远程工作就会变得极其困难。”-都柏林开发商 Conor McDermottroe
- 鼓励平等的机会。“我从未听说过决策过程中的推理,比如“[此人]不能参与此事,因为他们远离 CircleCI 的任何人。此外,我认为我们努力在互联网上分享信息和决策(例如 Slack 或 Google Docs),这样无论你是在本地还是远程,每个人都可以看到。”-东京开发商 Hirokuni Kim
- 拥抱多媒体。“与仅仅进行语音通话相比,进行视频会议要容易得多。没有视频会议,我无法远程完成这项工作。”-乔纳森·莫里斯,洛杉矶销售总监
- 聚在一起。定期举行面对面的全体会议,从我们可以围坐在一张餐桌旁的时候起,我们就一直在这样做。“全体会议是认识其他同事的好机会,让我们觉得我们有共同的目标。”-内特·史密斯,多伦多开发人员
小型全能运动队(在柏林也叫“小手”)
*### 你也能做到
这些是我们作为一家公司为保持我们的分布式组织或多或少平稳运行而做的一些事情。但是,作为一名远程工作者,在个人层面上并非没有挑战。在打开 Slack 和拨入 Zoom 的许多个早晨之后,我们的团队学到了一些东西。以下是一些让他们在别处工作的建议:
“如果这是你第一次远程工作,你会有几个月感觉‘失衡’和效率低下。很容易让你的工作/生活平衡向两个方向倾斜:工作不够或者工作太多。我避免工作太晚的个人生活窍门是有一个 6:30 到家的妻子,如果我让她等太久才吃饭,她会生气。这可能不是对每个人都有效,但在可能的情况下是有效的。”-加利福尼亚州索诺玛县开发人员 David Goeke
"养成良好的日常习惯."-Rose Kaplan-Bomberg,纽约成功工程师
“我强烈建议你不时到办公室来,与许多其他员工互动,并支持这些关系。”-乔纳森·莫里斯,洛杉矶销售总监
CircleCI 支持各种各样的多样性。阅读戴维·洛佩斯写给酷儿青年的信,了解作为一个酷儿在营销和面试时有什么帮助。
我想分享我在帮助酷儿青年方面学到的东西,让他们走进任何一家科技公司的大门,加入一个团队,拥抱他们的技能,支持他们的抱负,接受他们的身份。以下是对我有所帮助的:
想为一家重视贡献而非位置的公司工作吗?查看我们的空缺职位。*
使用 k6 | CircleCI 进行 HTTP 请求测试
本教程涵盖:
- 什么是 k6,它是如何工作的
- 编写和执行 k6 测试
- 分析 k6 测试结果
开发团队每天部署的许多多面应用程序是松散耦合的,每个服务的存在都是为了支持另一个服务。大多数开发 fullstack 应用程序的团队都知道测试这些服务之间的通信是必不可少的。该过程的一部分是测试 HTTP 请求端点,本教程正是关注于此。我将带领您学习如何扩展 k6 框架来测试我们的 HTTP 端点。您还将学习如何设置 k6 和,以及如何利用其他 API 测试框架中没有的特性。本教程在 k6 的性能测试 API 中继续。
先决条件
要学习本教程,您需要:
- JavaScript 的基础知识
- HTTP 请求和测试的基本知识
- 您系统上安装的 Node.js (版本> = 10.13)
- 一个圆的账户
- GitHub 的一个账户
我们的教程是平台无关的,但是使用 CircleCI 作为例子。如果你没有 CircleCI 账号,请在 注册一个免费的 。
k6 是什么?
k6 是一个开源框架,旨在为开发人员带来性能测试的乐趣。此时,您可能会问自己,这与 HTTP 请求测试有什么关系?测试性能意味着向 API 端点发出请求。我们已经在使用该工具进行 HTTP 请求,为什么不用它来测试那些端点呢?发出请求会将您带到测试端点的中途。我将在本教程的后面描述如何完成测试。
k6 用 goja 语言编写,是纯 Go 语言的 Ecmascript 5.1 实现。这种实现纯粹是出于性能原因,它包含了一些很棒的特性,使得具有 JavaScript 经验的软件开发人员可以很容易地进行测试。k6 附带了一个有用的 CLI,用于制作 API 支持的 k6 命令。k6 APIs 提供了对 JavaScript ES2015/ES6 的支持,以及负载测试的工具和功能,我们将在本教程的后续部分使用这些工具和功能。
既然我们知道了 k6 下运行的是什么,为什么不开始设置 k6 来运行我们的 HTTP 测试呢?
安装 k6
与 JavaScript 模块不同,k6 必须使用包管理器安装。在 macOS 中你可以使用自制。在 Windows 操作系统中,你可以使用巧克力糖。k6 文档中有更多适用于其他操作系统的安装选项。对于本教程,我们将遵循 macOS 安装指南。在 homebrew 中执行此命令:
brew install k6
这是您开始编写 k6 测试时需要运行的唯一命令。
安装 k6 后,我们需要创建一个文件夹来存储我们的项目。我们将通过在我们想要存储测试的目录中执行以下命令来做到这一点:
$ mkdir http-request-testing-with-k6;
$ touch todos-testing.js
这些命令将创建一个空项目,并创建我们的测试文件todos-testing.js
。
k6 测试结构
k6 使用的测试结构与大多数开发人员习惯的测试结构有点不同,尤其是那些来自 JavaScript 背景的开发人员。下面的代码片段显示了一个用 k6 编写的示例测试,声明我们正在从一个开源的 todo 应用程序 API 获得响应,我们将在本教程中使用该 API 进行测试。您可以向刚刚创建的项目中添加相同的测试。
// snippet from ./todos-testing.js
import http from 'k6/http';
import { check } from 'k6';
export let options = {
vus: 1,
};
export default function () {
group('API uptime check', () => {
const response = http.get('https://todo-app-barkend.herokuapp.com/todos/');
check(response, {
"status code should be 200": res => res.status === 200,
});
})
首先,如果您仔细观察测试,它类似于 JavaScript 测试代码,但是文件格式与我们通常编写 JavaScript 测试的方式不同。让我给你分解一下测试结构。
因为我们 k6 使用goja
而不是 JavaScript,所以我们只能使用 JavaScript 的某些方面来执行我们的测试。因此,我们不能访问像通常我们可以访问的describe
或it
块这样的方法,也不能访问像chai
这样的断言库。k6 提供了group()
和check()
方法,它们的工作方式与我们使用describe
和assert
的方式相同。group()
块允许我们在一个文件中编写多个测试,但是为了可读性,也可以将不同测试的配置分开。
k6 还捆绑了一个默认的HTTP
请求模块,我们可以用它来发出所有的 API 请求,无论是GET
POST
、PUT
还是DELETE
。当用纯 JavaScript 编写测试时,这个http()
方法相当于fetch()
。对于测试的其余部分,我们使用check()
方法断言响应是200
,并且我们可以继续使用这个断言块断言我们需要的任何其他响应。
提示:k6 测试中的options = {}
对象对于运行 HTTP 测试是可选的,但是当我们使用 K6 运行负载测试时,它非常方便。在这个特定的测试中,我们告诉 k6,我们希望只使用单个虚拟用户(vus)或者单个迭代来运行测试,这对于这个测试的上下文是有意义的。
k6 测试的生命周期
k6 遵循一个init code
、setup code
、VU code
和teardown code
的生命周期。这个循环显示了测试通常是如何运行的,以及测试在执行时可以访问哪些资源。下面是展示 k6 测试生命周期的示例代码块:
// 1\. init code
export function setup() {
// 2\. setup code
}
export default function (data) {
// 3\. VU code
}
export function teardown(data) {
// 4\. teardown code
}
init
和VU
阶段作为测试入口点,而teardown
和setup
提供了 API 测试可以在测试完成执行之前和之后运行的脚本。拆卸和安装方法是可选的,所以 k6 中最简单的测试形式可以只使用VU
代码方法,如下面的代码片段所示:
// snippet from ./todos-testing.js
export default function () {
const response = http.get('https://todo-app-barkend.herokuapp.com/todos/');
check(response, {
"status code should be 200": res => res.status === 200,
});
}
默认函数VU code
中的代码在为单次迭代(一次 VU)或者为负载测试的多次迭代调用测试时运行。
VU
代码发出 API HTTP 请求并执行断言,但是它不能导入其他模块或从文件系统加载文件。这就是 k6 在不同的执行模式下执行时知道哪些测试应该保存在内存中的原因。这种策略提高了 k6 的性能,优化了测试设计。
现在这变得有趣了,是时候将 CI/CD 集成到我们的应用程序中,这样您就可以执行测试了。对于本教程,我们将使用 CircleCI 为应用程序设置 CI/CD。
注意 : 如果您已经克隆了项目存储库,那么您可以跳过这部分教程。如果你想学习如何建立自己的项目,我在这里添加了一些步骤。
设置 Git 并推送到 CircleCI
要设置 CircleCI,通过运行以下命令初始化项目中的 Git 存储库:
git init
接下来,在根目录下创建一个.gitignore
文件。在文件中添加node_modules
来防止 npm 生成的模块被添加到您的远程存储库中。然后,添加一个提交,将你的项目推送到 GitHub 。
登录 CircleCI 并转到项目仪表板。您可以从与您的 GitHub 用户名或您的组织相关联的所有 GitHub 存储库列表中选择您想要设置的存储库。本教程的项目名为http-request-testing-with-k6
。在“项目”面板上,选择设置所需项目的选项。选择使用现有配置的选项。
注意: 在启动构建之后,预计您的管道会失败。您仍然需要将定制的.circleci/config.yml
配置文件添加到 GitHub 中,以便正确构建项目。
设置 CircleCI
在根目录下创建一个.circleci
目录,然后添加一个config.yml
文件。配置文件保存每个项目的 CircleCI 配置。在此配置中使用 CircleCI k6 orb
执行 k6 测试:
# snippet from .circleci/config.yml configuration file
version: 2.1
orbs:
k6io: k6io/test@1.1.0
workflows:
load_test:
jobs:
- k6io/test:
script: todos-testing.js
使用第三方球体
CircleCI orbs 是 yaml 配置的可重用包,它将代码压缩成一行。要允许使用像python@1.2
这样的第三方球体,您可能需要:
- 如果您是管理员,请启用组织设置,或者
- 向您组织的 CircleCI 管理员请求权限。
设置好配置后,将配置推送到 GitHub。CircleCI 将开始建设这个项目。
瞧啊。转到 CircleCI 仪表板,展开构建详细信息。验证测试运行成功,并集成到 CircleCI 中。
现在您已经设置了 CI 管道,您可以继续用 k6 编写更多的 HTTP 请求测试。
验证 k6 响应
既然您已经了解了 k6 的结构以及如何编写一个基本的测试,下一步就是用 k6 编写可伸缩的测试。使用您的todo
API 创建一个名为write k6 tests
的 todo 项目:
// snippet from ./todos-testing.js
group('Create a Todo', () => {
const response = http.post('https://todo-app-barkend.herokuapp.com/todos/',
{"task": "write k6 tests"}
);
todoID = response.json()._id;
check(response, {
"status code should be 200": res => res.status === 200,
});
check(response, {
"Response should have created todo": res => res.json().completed === false,
});
})
该代码块传递一个 todo 项,并向我们的 todo 应用程序 API 发出 HTTP 请求,这样就创建了您的 Todo 项。很简单,对吧?
为了使这更有趣,添加另一个测试来获取创建的 todo 项。这里的挑战是进入之前测试的范围。要做到这一点,需要为前面的测试返回的响应创建一个全局范围。然后在后续测试中使用 todo 项的Id
。这里有一个例子:
// snippet from ./todos-testing.js
group('get a todo item', () => {
const response = http.get(`https://todo-app-barkend.herokuapp.com/todos/${todoID}`
);
check(response, {
"status code should be 200": res => res.status === 200,
});
check(response, {
"response should have the created todo": res => res.json()[0]._id === todoID,
});
check(response, {
"response should have the correct state": res => res.json()[0].completed === false,
});
})
该测试验证创建的 todo 项与您创建的是同一项,并且其属性没有更改。在本地运行这个测试成功通过,表明就像在 JavaScript 测试中一样,k6 可以在测试中共享状态。
这个示例代码中还显示,使用groups()
来分离不相关的测试会在测试失败时增加松散耦合。它还提高了测试的可读性。
使用场景为多个环境配置 k6
作为一个负载测试工具,k6 附带了一些很棒的特性,可以在不同的环境中执行一些操作,比如编写测试,而不需要太多的配置。scenario
特性就是一个很好的例子。场景提供 k6 测试的深度配置,使得根据配置偏好配置每个单独的 VU
成为可能。
export let options = {
scenarios: {
example_scenario: {
env: { EXAMPLEVAR: 'testing' },
tags: { example_tag: 'testing' },
},
}
}
这个代码块展示了如何将场景对象捆绑在 k6 options
对象中。它传递包含不同环境的环境配置的env
对象。金矿!
要自己做这件事,创建一个名为environmentConfig.js
的文件,或者使用克隆的存储库中的文件。为开发和试运行环境添加一个配置,并将它们传递给不同的测试。
// snippet from ./environmentConfig.js
export function developmentConfig(filename) {
let envConfig = {
BASE_URL: "http://todo-app-barkend.herokuapp.com/todos/",
ENV: "DEVELOPMENT",
};
return Object.assign({}, envConfig, filename);
}
export function stagingConfig(filename) {
let envConfig = {
BASE_URL: "https://todo-app-barkend.herokuapp.com/todos/",
ENV: "STAGING",
};
return Object.assign({}, envConfig, filename);
}
这个代码块展示了如何为不同的环境配置测试。注意,它为开发环境使用了一个HTTP
(非 SSL) URL,为登台环境使用了一个HTTPS
(支持 SSL)URL。
一旦您为单个环境设置了变量,您就可以使用场景使用options
对象将它们导入到不同的测试中。创建两个新文件来测试这个特性,一个用于开发环境,一个用于测试环境。将此代码片段用于开发环境测试:
// snippet from scenario-tests/todos-development-tests.js
import { developmentConfig } from '../environmentConfig.js';
export const options = {
scenarios: {
example_scenario: {
env: developmentConfig(),
executor: 'shared-iterations',
vus: 1
}
}
};
export default function () {
group('API uptime check - development', () => {
const response = http.get(`${__ENV.BASE_URL}`);
check(response, {
"status code should be 200": res => res.status === 200,
});
});
…
});
这个代码块展示了如何利用scenarios
配置,同时在不同的环境中运行同一组测试。
注意 : 可以在克隆的存储库中的scenarios-tests
文件夹中找到不同配置的用于测试和开发的完整测试。
使用这种方法,您可以在DEV
、UAT
,甚至PROD
环境中运行测试,即使相同测试的配置对于每个环境是不同的。为了验证成功,您可以运行scenario-tests
文件夹中的测试。
对于开发环境/配置,运行:
K6 run scenario-tests/todos-development-tests.js
对于暂存环境,运行:
K6 run scenario-tests/todos-staging-tests.js
为了确保这些测试在 CI/CD 管道上运行,您需要修改.circleci/config.yml
来包含这些运行命令:
# snippet from .circleci/config.yml configuration file
jobs:
- k6io/test:
script: todos-testing.js
# Add more jobs here
- k6io/test:
script: scenario-tests/todos-development-tests.js
- k6io/test:
script: scenario-tests/todos-development-tests.js
场景允许您将 k6 测试配置为单独的迭代。当您希望在一个文件中编写多个负载测试场景,并为每个场景使用不同的配置时,它们提供了可扩展性。
在 CircleCI 验证管道成功
通过本教程,我们已经能够成功地运行我们的测试,但是这并不能证明它们将总是在 CI 上工作。为了增加我们对这个过程的信心,让我们提交我们的更改并再次推送到 GitHub。由于我们已经配置了 CircleCI,一旦更改被推送到 GitHub 远程存储库,构建应该会自动开始。
万岁!我们对三个测试文件的所有构建都进行了绿色检查。这只能意味着一件事:庆祝时间!
结论
在本教程中,我们了解了什么是 k6 框架以及它是如何工作的。我们了解到它是用goja
语言创建的,但是是为使用 ES6 JavaScript 语法而编写的,这优化了它作为负载测试工具的性能。我们还学习了 k6 测试的不同生命周期阶段,以及如何编写和断言 k6 测试。我们学习了如何在多种环境中配置 k6,并利用了 k6 中的options
和scenarios
对象。现在前进,走向成功!
通过完成使用 k6 的性能测试 API 教程,以您所学为基础。
Waweru Mwaura 是一名软件工程师,也是一名专门研究质量工程的终身学习者。他是 Packt 的作者,喜欢阅读工程、金融和技术方面的书籍。你可以在他的网页简介上了解更多关于他的信息。
工程读书俱乐部| CircleCI
原文:https://circleci.com/blog/if-you-want-your-engineers-feedback-on-your-stack-start-a-book-club/
15 名工程师在一个周五的下午参加了一个长达一小时的视频会议。有团队会议吗?也许是周末前需要修复的一个紧迫问题?事实证明,工程师们都是来讨论…一篇文章的。
是的,他们正在开会讨论一篇关于分布式系统的文章,事实证明,这是 eng 团队成员在架构决策中拥有发言权的最有价值的方式之一。在过去的一年里,CircleCI 的工程师们每个月都会聚在一起,讨论一篇关于工程热门话题的新文章、论文或视频,这是工程阅读俱乐部的一部分(尽管该俱乐部最初是一个“书籍”俱乐部,但像科技领域的其他任何东西一样,它必须不断发展,以更好地满足其“用户”的需求和限制对于忙碌的工程师来说,花时间阅读一本完整的书是一个很高的门槛,因此该团队将其重新设想为一个更普遍的阅读俱乐部,以鼓励参与)。
然而,这个俱乐部不仅仅是一个社区建设的实践,它旨在将有趣的主题带到前台,并使工程师能够就他们每天使用的工具和系统做出决定。
按照行业惯例,关于技术堆栈和产品方向的决策通常来自最高领导层。首席技术官就一个新的系统或工具打电话,工程经理在他们的团队中实施变更。当做出这类重大决策时,很难从团队的每个成员那里收集到真实的反馈。在 CircleCI,我们发现让大家自由讨论的最有效的方法之一是,有点令人惊讶地,通过阅读俱乐部。
俱乐部鼓励自下而上的思想领导。因为团队成员每个月都会选择主题,谈话和辩论自由流动,想法会沿着指挥链向上而不是向下传递。对于团队来说,这一小时的承诺是非常值得的。它让他们挑战我们既定的理念和实践,发现新技术,并激发整个组织的变革和发展。正如俱乐部主持人和高级发布工程师 Michael Marquez 指出的那样,讨论总是让团队成员对工程工具和哲学有一个细致入微的看法——这不仅仅是“这是做这件事的正确方法”,而是要复杂得多:
“我从这次经历中学到的是,没有解决所有问题的神奇方法,只有权衡。没有完美的架构,也没有完美的测试。随着行业的发展和进步,我们也在发展。”
实践持续改进的心态
俱乐部给予会员挑战现状的自由,以努力不断改进团队和公司。事实上,俱乐部的主要目的是选择激发组织变革的主题——无论这意味着探索一种新工具,挑战团队的结构,还是头脑风暴一项新功能。当有争议的话题出现时,比如生产中的测试,来自不同工程团队的不同经验水平的工程师就可以参与进来。俱乐部甚至将持续学习的理念写入了他们的使命宣言:
“[阅读]俱乐部的目标是通过书籍、视频或讨论主题探索与工程和工程最佳实践相关的主题,以努力促进个人和公司的专业发展。最终目标是将会议中任何有价值的教训整合到我们的团队和公司中。”
团队积极地将这一使命付诸实践。例如,在一次关于基于消费者的合同测试的会议之后,来自俱乐部的工程师们组成了一个小型的 tiger 团队,看看他们是否可以为该环境组装一个原型。有时候,这些活跃的读书俱乐部讨论催生了这样的草根倡议。不过,更常见的情况是,更好的工具、系统或实践的想法会被平台副总裁 Michael Stahnke 和 CTO Rob Zuber 采纳,他们会将反馈纳入架构决策。
阅读/观看列表
回顾一下我们在过去几个月里读到的内容:
6 月- 将微服务扩展到前端
7 月- 验证微服务与合同测试的集成
八月- 保持主果岭的规模
9 月- 年轻血液分布式系统笔记
10 月- 是的,我在生产中测试(你也是)
结束语
工程读书会(fka 读书会)不仅仅是团队成员每个月聚在一起讨论有趣话题的借口。这是一个创意产生和辩论的创造性空间,实践了我们组织和产品的核心价值。如果你想成立自己的工程读书会,我们有以下建议:
-
让工程团队的成员来主持会议,而不是高层管理人员。
-
合理设定你的范围。选择适合你的团队的会议节奏,选择参与者有时间阅读或观看的文章、视频或书籍。
-
为每次会议选择一个团队感兴趣的主题,以保持讨论活跃;你不必拘泥于 CTO 在读什么。
如果你成立了自己的阅读俱乐部,请发推特@CircleCI 告诉我们进展如何。
7 月 19 日事件事后分析:发生了什么,下一步是什么
原文:https://circleci.com/blog/incident-postmortem-for-july-19-what-happened-and-what-s-next/
7 月 19 日,CircleCI 面临站点范围的中断,这使得数千个团队在一天的大部分时间里无法测试和部署构建。这次中断影响了许多开发团队的生产力,并且肯定导致了一些错过的最后期限。我们重视客户对我们的信任,并对由此给他们的工作带来的影响深感抱歉。对于那些感兴趣的人,我们想给出更多关于发生了什么,为什么会发生,以及我们正在做什么的细节。
发生了什么事?
世界协调时 2018-07-19 16:46:14,CircleCI 的一个内部证书颁发机构(CA)的根证书意外过期,导致该 CA 颁发的所有证书同时失效。正在讨论的 CA 用于 CircleCI 环境中运行的所有 Mongo 实例(总共 17 台主机)。使用内部 CA 要求将根证书分发给每个客户端,以便建立信任关系。由于影响范围,数百台主机和容器受到影响。为了避免重写每个客户端主机的证书库,我们为所有 Mongo 服务器生成了第三方证书,并重新配置了服务器以使用这些证书。
我们是怎么到这里的?
在 2015 年夏天,在 CircleCI 雇佣第一个 SRE 团队成员之前,当我们的第三方 Mongo 托管提供商一直让我们失望时,我们开始构建一套内部管理的 Mongo 服务器,我们可以扩展这些服务器以满足我们的需求,并使用我们认为更适合我们提供的服务的工具进行管理。虽然我们已经把目光放在了离开 Mongo 上,但我们也知道我们可能会在未来很长一段时间内使用它。2015 年 8 月初,在构建最终成为 5 个独立副本集的第一个副本集时,我们创建了一个内部证书颁发机构,开始为我们的副本集颁发证书。该证书的有效期为 10 年,以避免在处理关键基础设施的内部轮换证书时遇到一些挑战。做出这个决定的时候,还没有像今天这样方便地轮换证书的工具。
在 2015 年 9 月下旬,当我们准备开始将流量迁移到我们的新 Mongo 集群时,一名审查人员发现用于签署我们的服务器证书的根证书正在使用 SHA1 作为签名算法。该证书立即被替换为一个新的证书,它使用 SHA512 作为签名算法。其意图是该证书也将有 10 年的有效期。然而,我们最近发现,情况并非如此。虽然我们无法访问机器,因此无法访问创建该证书的原始命令,但很明显,操作员的错误导致生成的根证书的有效期较短。
我们用这个根 CA 生成和签名的所有特定于服务器的证书都有 10 年的有效期,我们检查了这些证书以确保我们不急于替换它们。
为了避免这种情况再次发生,我们要改变什么?
避免此类事件发生的大部分工作是我们已经完成的工作。在我们部署 Mongo 基础设施以来的这段时间里,我们的 SRE 团队成员从 0 人增加到了 9 人,我们在运营基础设施方面投入了大量资金。我们现在使用自动化工具来管理我们的内部证书,并使用多个第三方来处理我们的整体 TLS 证书加载。我们还监控随后构建的所有系统的证书到期时间。
不幸的是,基于我们有一个相当大的窗口来处理工具的迁移,我们允许我们的 Mongo 基础设施上的证书管理的迁移被去优先级化。我们目前正在审核我们在整个基础设施中对 TLS 的所有使用,以识别任何没有使用我们工具的最新标准的配置。我们还在寻找旧系统基础设施上的任何其他非标准配置,以使我们的所有系统达到我们当前的监控和维护工具水平。具体到此次事件中的 Mongo 服务器,我们将来自内部 CA 的证书替换为外部提供的有效期为 1 年的证书,现在我们已经清除了该事件,将积极地将它们迁移到我们的公共基础架构。
我们还学到了什么?
我们有一个工程团队,非常重视同行代码审查和自动化,以便在错误进入生产之前将其捕获。这是我们如此依赖基础设施而不是代码的原因之一。但是,即使在这些工具还没有很好开发的时候,我们还没有把它们中的一些放在适当的位置上,仍然有可能以手工的方式进行同行评审。当采取有风险的行动时,我们经常这样做。一句简单的“我要用这个命令做这件事”来获得第二双眼睛的“LGTM”总是值得的。
CircleCI 的事故+中断:我们的剧本和我们学到的东西
原文:https://circleci.com/blog/incidents-outages-at-circleci-our-playbook-and-what-we-ve-learned/
来自出版商的说明:您已经找到了我们的一些旧内容,这些内容可能已经过时和/或不正确。尝试在我们的文档或博客中搜索最新信息。
二月份,当 AWS 经历了 S3 的中断时,CircleCI(和基本上一半的互联网)受到了严重影响。虽然停机从来都不好玩,但它是检查您的事故计划、团队合作以及改进您的系统和性能的最佳机会。
虽然我们尽了最大努力来提供不间断的服务,但我们(很少)会遇到服务质量下降,甚至中断的情况。有时,这是因为我们团队引入的问题,或者我们犯的错误。
此外,我们还依赖于许多其他服务(GitHub、Bitbucket、AWS、Heroku 等)。).因此,当其中一个或多个经历停机时,我们也会感到痛苦。
以下是我们所做的——在某些情况下,当事情变得不顺利时,我们是如何艰难地学会做这件事的。
有很多不同的方法来处理事件(只是谷歌“事件响应”),但有几件事是所有人都有的,那就是首先要有一个计划,无论多么简单,其次要遵循计划。这两者现在看起来都很明显,但令人惊讶的是,有多少人认为他们可以让聪明的工程师解决问题,并以此作为他们的“回应”。
我们事故响应计划的参数
在 CircleCI,我们的事故由许多团队的人员管理,我们都使用许多规则:
-
任何人都可以宣布事故。通常不是 SRE 团队或工程师注意到事情“不太对劲”
-
一旦宣布发生事故,对话将转移到我们的#incident 聊天室,这有助于整合有关事故的所有信息。
-
然后,我们决定由谁来扮演两个核心角色:指挥官和通信人员(我将在后面的文章中详细介绍)
- 事故指挥官-负责事故的人员
- 通信-负责状态更新的人员
-
确定谁在工程部门提供帮助
事故期间响应指南
在我们满足了上面的标准之后,我们开始调试并确定中断的根本原因。我们通常也开始确定需要什么样的临时变更来处理停机似乎总是会产生的级联“混乱”。
在事件响应的最开始,您需要明确谁在扮演上述角色。事故指挥官需要是不一定致力于解决事故但也必须完全在场的人-他们是确保评论和小待办事项不会被忘记的人。他们的另一个主要任务是确保沟通渠道没有无关的闲聊。
事故指挥官还需要非常依赖通信人员,这样他们就不会陷入在事故中经常出现的“嘿,状态如何”的问题中——通信人员也是确保状态页和其他面向客户的通信等项目得到干净处理的人。
我们采用了一种状态策略,通信人员通过使用 20 分钟计时器提醒团队需要更新,然后指挥官将推荐更新,通信人员将按照惊人的风格和语气指南(包括状态消息的示例)进行修改。这些例子是由我们的营销团队编写的,让我们在深陷问题的时候,可以避开文字推敲。
一旦确定了事件的根本原因,指挥官将指示通信人员,我们需要将事件状态更改为“已识别”。当我们部署一个补丁时,以及当我们确信这个补丁解决了问题时,也会发生类似的变化。修复得到验证后,我们会维持 30 分钟的最终“监控”阶段,以确保事件得到真正解决。
我们的事件响应计划的一个关键部分是,我们还要确保响应事件的每个人都有机会休息、获得食物和其他自我护理——如果团队没有足够的睡眠、食物或思考时间,任何事情都无法解决。
我们关注自我护理的另一个方面是了解一个事件是由整个团队负责的,这使我们能够利用位于多个时区的员工。长时间运行的事件通常会跨越时区,因为它们流向该时区的工作日。让事故“全天候”运行的能力确实是可能的,因为我们努力确保我们系统的知识在我们所有的团队中传播。
惨痛的教训
我们的事件响应计划中的一些其他项目我们不得不艰难地学习:)
- 我们不会在事故期间更改服务器数量,尤其是在与 AWS 相关的事故期间。AWS 经常限制 API 调用,然后你最终会与成千上万也在尝试启动实例的其他公司竞争。
- 在可能的情况下,我们通过关闭低优先级的后台进程来释放额外的资源,从而减轻负载。
- 我们将#incident Slack 渠道中的闲聊和猜测保持在最低限度,将附带讨论重定向到我们正常的#ops 和#engineering 渠道。不参与事故处理的工程师监控#incident 以了解所涉及的问题并不罕见。把#incident 无情地保持在话题上需要一些练习和自律,但是可以做到。
- 如果合适的话,我们还会禁用某些功能,以减少客户流失。这方面的一个例子是我们对所有“循环调试”作业的自动重试,如果在外部中断期间让它继续运行,重试次数很容易淹没我们的作业队列。
事件后行动项目
事件结束后,真正的工作才开始。即使只有事故指挥官审查日志并更新文档和/或操作手册,您也应该始终进行事故事后分析。如果事件是外部的,您仍然可以在基础架构中发现可以改进的边缘情况或单点故障。如果他们因为各种各样的现实原因而无法改善,那么至少在他们周围增加监控,这样你就可以在行为变成事故之前得到警告。
事后分析之后,创建事故报告并在内部发布。在公共场所张贴我们的事件报告是我们在收到客户反馈后才开始做的事情,他们非常有兴趣了解事件的“原因”和“方式”,因此我们将此添加到了事件清单中。
结案建议
关于事故响应计划,我有两个最后的建议。第一个建议是,你应该在每次事故后回顾你的计划,看看如何改进。多年来,我们的计划发生了重大变化,更新计划是获取和保存有关事件响应的知识和最佳实践的最佳方式。
第二个建议是确保每个人都知道你的事件响应计划,并知道如何使用它。像许多事情一样,如果你的团队不知道这个计划,不知道在哪里找到它,或者不知道如何实现它,那么这个计划是没有用的。
提高数据科学和机器学习项目的可靠性
数据科学不再是公司的小众话题。从首席执行官到实习生,每个人都知道采取科学方法处理数据是多么有价值。因此,许多不直接从事软件工程领域的人开始编写更多的代码,通常是以交互式笔记本的形式,如 Jupyter。软件工程师通常是构建系统、代码静态分析和生成可重复过程以加强质量的巨大倡导者。写代码 Jupyter 笔记本的商务人士呢?他们可以使用哪些流程来使他们的数据科学、机器学习和 AI 代码更加可靠?
数据科学项目质量
提高数据科学软件质量的一个方法是创建一个确保质量和可重复性的项目结构。要做到这一点,可以从传统的软件工程世界中汲取一些思想。Brian Kernigan 是《AWK 编程语言》和《K 和 R C》的合著者,他在《软件工具》一书中总结了软件开发的真正本质,他说:“控制复杂性是软件开发的本质。”
在我以前写的一篇关于代码质量的文章中,关于 Python 中的软件工程项目质量,我说过如下的话:
“编写高质量代码的第一步是重新审视个人或团队如何开发软件的整个思维过程。通常,在失败的或有问题的软件开发项目中,软件是在一种反动的意识流中开发的,软件开发的焦点是以任何可能的方式解决问题。在一个成功的软件项目中,开发人员不仅要考虑如何解决手头的问题,还要考虑解决问题的过程。
一个成功的软件开发人员会设计出一种容易自动化的方式来运行测试,这样他们就可以不断地证明软件是有效的。他们意识到不必要的复杂性的危险。他们态度谦逊,寻求批判性的评论,并期望在每一步都进行重构。他们不断地思考如何确保他们的软件是可测试的、可读的和可维护的。"
数据科学项目也是如此;需要一种自动化的方法来确保质量。幸运的是,有了 CircleCI 和开源库这样的服务,这很容易实现。在下面的章节中,我们将一步一步地演示这一点。
数据科学项目自动化测试设置
为数据科学项目建立适当的自动化测试的最好方法之一是从一开始就正确地设置它。那看起来像什么?
- 创建一个 GitHub 项目。创建一个像这样的新项目示例回购。
- 创建一个包含一个
config.yml
文件的.circleci
目录。这个是你可以参考的config.yml
的例子。 - 创建一个
.gitignore
文件。忽略不重要的文件是很重要的。 - 创建一个
README.md
文件。一个好的README.md
应该能够展示用户如何构建项目以及项目做什么。包含一个显示 CircleCI 构建状态的徽章也很有帮助,比如这个例子。 - 创建一个
Makefile
。一个Makefile
是一种在构建过程中运行步骤的常见方式,已经存在了几十年…因为某种原因…它们只是工作。我们将介绍如何为数据科学项目设置这一点。 - 其他可选的重要文件和目录有:库目录、命令行工具、requirements.txt 和测试目录。
一个很好的起点是将一个Makefile
作为模板。myrepo/Master/Makefile
的内容如下所示,可以在这里找到:
setup:
python3 -m venv ~/.myrepo
install:
pip install -r requirements.txt
test:
python -m pytest -vv --cov=myrepolib tests/*.py
python -m pytest --nbval notebook.ipynb
lint:
pylint --disable=R,C myrepolib cli web
all: install lint test
关键步骤有:setup
、install
、test
、lint
、all
(运行一切)。设置步骤会创建一个可选的虚拟环境,稍后可以通过运行以下命令来获得该环境:
source ~/.myrepo/bin/activate`
可以作为make install
运行的install
步骤安装 requirements.txt 文件中列出的包。这里的就是一个例子。
如果创建了库、命令行工具或 web 应用程序,那么lint
步骤是有意义的,可以使用make install
运行。仅仅在 Jupyter 笔记本上运行是没有意义的,但是它确实有助于保持与项目相关的代码的质量。下面是 lint 的输出示例,也可以在这里找到:
(.myrepo) ➜ myrepo git:(master) ✗ make lint
pylint --disable=R,C myrepolib cli web
No config file found, using default configuration
--------------------------------------------------------------------
Your code has been rated at 10.00/10 (previous run: 10.00/10, +0.00)
最后也是最重要的一步是运行make test
。这使用了pytest
和 nbval
插件。输出如下所示,也可以在这里找到。
(.myrepo) ➜ myrepo git:(master) ✗ make test
python -m pytest -vv --cov=myrepolib tests/*.py
============================================================ test session starts ============================================================
platform darwin -- Python 3.6.4, pytest-3.3.0, py-1.5.2, pluggy-0.6.0 -- /Users/noahgift/.myrepo/bin/python
cachedir: .cache
rootdir: /Users/noahgift/src/myrepo, inifile:
plugins: cov-2.5.1, nbval-0.7
collected 1 item
tests/test_myrepo.py::test_func PASSED [100%]
---------- coverage: platform darwin, python 3.6.4-final-0 -----------
Name Stmts Miss Cover
-------------------------------------------
myrepolib/__init__.py 1 0 100%
myrepolib/repomod.py 11 4 64%
-------------------------------------------
TOTAL 12 4 67%
========================================================= 1 passed in 0.02 seconds ==========================================================
python -m pytest --nbval notebook.ipynb
============================================================ test session starts ============================================================
platform darwin -- Python 3.6.4, pytest-3.3.0, py-1.5.2, pluggy-0.6.0
rootdir: /Users/noahgift/src/myrepo, inifile:
plugins: cov-2.5.1, nbval-0.7
collected 4 items
notebook.ipynb .... [100%]
===================================================================== warnings summary ======================================================================
notebook.ipynb::Cell 0
/Users/noahgift/.myrepo/lib/python3.6/site-packages/jupyter_client/connect.py:157: RuntimeWarning: Failed to set sticky bit on '/var/folders/vl/sskrtrf17nz4nww5zr1b64980000gn/T': [Errno 1] Operation not permitted: '/var/folders/vl/sskrtrf17nz4nww5zr1b64980000gn/T'
RuntimeWarning,
-- Docs: http://doc.pytest.org/en/latest/warnings.html
=========================================================== 4 passed, 1 warnings in 2.08 seconds ============================================================
有必要解释一下nbval
插件是如何工作的。简而言之,它为您运行 Jupyter 笔记本,并确保所有的单元格都执行。有两种模式可以使用:一种实际检查每个单元的输出,另一种不检查。检查每个单元的输出的方法可能有点棘手,因为很多时候随机图像或输出都在单元中,并且测试将在每次后续运行中失败。
所有这些都解决了之后,让 CircleCI 运行起来就没什么可做的了。该信息包含在 CircleCI 文档中。圣代的最后一个收获是让徽章发挥作用,这也包含在官方文件中,在本文分享的回购中有一个例子。
摘要
本文展示了如何引导一个数据科学项目,设置 Github 结构,运行测试,然后将其发送到 CircleCI 进行构建。我在 YouTube 上制作了一个视频,展示了如何安装和测试这个项目。另一个值得关注的资源是阅读《实用人工智能:基于云的机器学习导论》一书,了解我是如何使用 CircleCI 的。参考资料中有相关链接。
Noah Gift 是加州大学戴维斯分校管理研究生院 MSBA 项目和 MSDS 西北大学研究生数据科学项目的讲师和顾问,他在那里教授和设计研究生机器学习、人工智能和数据科学课程,并为学生和教师提供机器学习和云架构方面的咨询。他已经发表了近 100 篇技术出版物,包括两本关于从云机器学习到 DevOps 等主题的书籍。他最近的一本书是《实用人工智能:基于云的机器学习导论》(Pearson,2018)。
参考
在 CircleCI - CircleCI 上用纱线取代 NPM
原文:https://circleci.com/blog/install-and-use-yarn-the-npm-replacement-on-circleci/
来自出版商的说明:您已经找到了我们的一些旧内容,这些内容可能已经过时和/或不正确。尝试在我们的文档或博客中搜索最新信息。
Yarn 是一个开源的 JavaScript 包管理器。CircleCI 可以缓存 Yarn 和它安装的包。这可能会加快构建速度,但更重要的是,可以减少与网络连接相关的错误。
要了解更多关于如何在 CircleCI 构建中安装 Yarn 的信息——包括完整的示例——请阅读我们的文档。
Yarn 是谷歌、脸书、Exponent 和 Tilde 合作的成果,于 2016 年 10 月发布。要了解更多关于纱线的信息,你可以查看他们的回购或脸书上的公告。
在 5 分钟或更短时间内安装自托管转轮| CircleCI
原文:https://circleci.com/blog/install-runner-in-five-minutes/
在 CircleCI 用户界面中快速轻松地设置和实时跟踪跑步者
我们最近修改了我们的免费增值计划,成为这个星球上对开发者最慷慨的免费 CI/CD 层。除了在免费计划中提供强大的功能和资源,我们还将自托管跑步者扩展到了所有 CircleCI 计划。
丰富免费计划的功能是不够的,所以我们努力使我们的平台对所有技能和规模的开发者尽可能友好和直观。今天,我们很高兴为自主跑步者推出新的简化用户体验。我们已经在 UI 中添加了对自托管跑步者的一流支持。无论您是对数百万用户的下一个伟大的移动应用程序进行代码签名,还是在地下室的 Raspberry Pi 上测试新固件,您都可以无缝地利用 CircleCI 的自托管运行程序来完成工作。
现在,您可以在不到 5 分钟的时间内快速开始安装和使用自托管运行程序,并通过 UI 获得全新的安装体验。我们还将帮助您在单一视图中跟踪您的所有跑步者活动,以便您可以监控和调整您的自托管跑步者池,以满足您的云管道的需求,做出明智的扩展决策,并识别和修复停滞的作业或失败的基础架构。
在 5 分钟或更短的时间内开始自主跑步
首先,在 CircleCI UI 中快速轻松地配置您的第一个 runner 资源类,而无需下载额外的软件。资源类是标签,使您能够为特定的作业子集(即对于将在 macOS 机器上运行的作业,您可能有一个资源类,对于将在 Linux EC2 实例上运行的作业,您可能有一个资源类。
要创建您的第一个资源类,请访问 CircleCI UI 中的“Self-Hosted Runners”选项卡,以创建您的名称空间(您的组织拥有的唯一标识符)和资源类。创建名称空间后,按照自导式安装流程安装您的第一个自托管 runner。
一旦您在 UI 中确认检测到新的自托管运行程序,您就可以使用 UI 中显示的示例配置文件,或者使用现有的配置文件来运行新安装的自托管运行程序的作业。
请参见文档以获取支持的操作系统、版本和架构的最新列表。
实时跟踪您的自主跑步者
在跑步者设置和安装之后,CircleCI UI 现在跟踪活动的跑步者代理,并维护与您的帐户相关联的跑步者代理的显示。该显示器包括活动和备用流道的实时视图,有助于为扩展决策提供信息,并使卡住的作业或失败的基础设施能够快速识别并轻松修复。
为您的 CircleCI 帐户激活自托管跑步者用户界面
要将自托管跑步者作为 CircleCI 云设置的一部分,CircleCI 帐户的管理员应导航至app.circleci.com
,然后:
- 转到组织设置页面
- 点击自助跑步者
- 接受跑步者条款
你可以在 CircleCI 学院的自助跑步者课程中了解更多关于自助跑步者健身的信息。
下一步是什么?
查看我们的社区论坛,了解如何开始使用 app.circleci.com。
问题/评论?
如果您有关于如何改善跑步者体验的想法,请访问 Canny 浏览或提交新想法。前往我们的社区论坛,讨论,让我们知道您如何使用 runner。更多详细信息,请访问文档。
用扭锁和圆环扫描集装箱图像
开发人员和 DevOps 团队是采用容器的主要驱动力。DevSecOps 的实践将安全性嵌入到当今的现代工作流中,而不会增加来自组织安全方面的不必要的摩擦。这并不意味着安全团队被排除在外。相反:通过与开发人员已经在使用的工具(如 CircleCI)集成,安全团队制定的标准将作为构建和部署过程的一部分不断得到应用。
通过在容器映像在生产环境中运行之前对其进行扫描来实现 DevSecOps,可以产生一些好处,例如向开发人员提供快速反馈,以及将不安全或不符合要求的工作负载排除在生产环境之外。与安全和合规性相关的质量关来自与安全团队的协商,并作为 CI 流程的一部分自动完成。因此,开发人员可以快速获得反馈,并可以在开发某个功能时修复安全漏洞和合规性问题,而不会产生上下文切换的成本,或者更糟糕的是,将易受攻击的代码发布到产品中的风险。通过这种方式,在 CI/CD 过程中设置安全性和遵从性质量关口可以极大地增强开发人员容器的安全性,而不会降低它们的速度。
通过 CircleCI Orb 注册表使用 Twistlock
扭锁球可以在 CircleCI Orb 注册表中找到。此外,我们的 GitHub repo 包括关于配置 Twistlock 许可证、在 Twistlock 中为 CI 用户角色设置凭证的关键细节,以及其他可能有帮助的参数、命令和脚本。
使用 twistcli 扫描图像
CircleCI orb 利用了我们的命令行控制和配置工具twistcli
。twistcli
工具支持扫描图像以发现漏洞和合规性问题,并且无需原生插件即可与任何 CI 工作流集成。
下面,您可以看到一个示例.circleci/config.yml
文件,它将在 CircleCI 中的构建之后扫描您的图像,然后将图像推送到您的容器注册表:
version: 2.1
orbs:
twistcli: twistlock/twistcli-scan@1.0.4
jobs:
docker-build-and-save:
executor: twistcli/default
steps:
- checkout
- run: 'docker build -t myrepo/myimage:tag .'
- run: mkdir -p workspace
- run: 'docker save myrepo/myimage:tag -o workspace/image.tar'
- persist_to_workspace:
root: workspace
paths:
- image.tar
workflows:
scan-image:
jobs:
- docker-build-and-save
- twistcli/scan-image:
requires:
- docker-build-and-save
context: tl_scan_context
image: 'myrepo/myimage:tag'
imagetar: image.tar
vuln-thresh: critical
comp-thresh: ''
only-fixed: true
在示例config.yml
文件中,vuln-thresh
和comp-thresh
指的是 Twistlock 将在每个构建中警告或阻止的特定严重性级别。虽然许多用户可能会选择简单地扫描他们的映像以查找漏洞或合规性问题,但您可以自定义这些设置,以阻止构建在映像不符合您的安全要求时将映像推送到您的注册表中(如下图所示)。例如,如果有已知的供应商修补程序,许多用户会选择阻止关键漏洞进入他们的容器注册表。
此外,您可以选择将only-fixed
设置为 true 或 false,以仅识别具有已知供应商修补程序的问题。
要深入了解整个样本config.yml
文件,您可以跳到 Twistlock orb GitHub repo 的这个特定部分。
在 CircleCI 中查看扫描结果
一旦配置了 CI 用户角色和脚本,您就可以在 CircleCI 和 Twistlock 控制台中看到每个构建的漏洞扫描结果。下面,您可以看到一个 CircleCI 工作流示例,我在其中扫描了一个 Docker 版本:
此外,我可以查看详细的扫描结果,包括表面 CVEs、软件包信息、供应商修复状态和严重性。我还可以看到针对 300 多项 Docker、Kubernetes 和 Linux CIS 基准的合规性检查:
如果您对跨团队和环境的所有扫描结果的更全局视图感兴趣,您可以通过导航到监控>漏洞> Twistcli 扫描在 Twistlock 控制台中查看所有扫描。在那里,您可以看到每个构建的状态,或者单击任何扫描来查看更详细的扫描结果,就像在 CircleCI 中一样。在下面的屏幕截图中,“Status”列显示我的所有扫描都符合我的策略要求,只有靠近底部的一个扫描不符合我的策略要求:
摘要
我们很自豪能够与 CircleCI 合作,将安全性嵌入到 DevOps 工作流中。要了解更多关于您和您的团队如何操作 DevSecOps 的信息,请查看我们的信息图 7 个提示,以导航操作 DevSecOps 。
Jeremy Adams 为 Twistlock 带来了超过 10 年的 IT 运营和自动化经验。在那里,他与整个云原生生态系统的合作伙伴合作,将安全性集成到他们的 DevOps 工作流中,以发布安全的应用程序并保护他们免受主动威胁。此前,Jeremy 曾在 Puppet 和 Sun Microsystems 担任以客户为中心的技术职务。他是一名退伍军人,快乐地移居到俄勒冈州的波特兰。
带 CircleCI 的智能 CI/CD:打造我们的 autoscaler - CircleCI
原文:https://circleci.com/blog/intelligent-ci-cd-with-circleci-building-our-autoscaler/
当 CircleCI 客户想要开始一个新的构建时,预先预热、预先调配的虚拟机已准备就绪,并且所有依赖项都已安装,可以一周 7 天、一天 24 小时提供服务。CircleCI 机器团队的软件工程师卡宴·盖修说:“顾客是看不见的,这是那种(我们的顾客)只希望能工作的东西。”
但是,当需求日复一日、周复一周不断波动时,我们如何管理随时准备就绪的虚拟机群呢?或者,例如,当 Xcode 映像更新时,我们如何快速转移资源,并且我们需要快速重新分配映像版本以匹配使用情况?
在过去的一年里,这些问题的答案发生了变化,在某种程度上改善了客户在 CircleCI 上运行构建的体验,但对于使用该服务的人来说,这可能不会立即被注意到。以前,我们的流程涉及手动调整资源和基础映像的每个组合的比例级别。我们维护了固定数量的机器,但是客户的需求波动很大。当需求激增时,我们的团队开始行动,调整可用机器的数量和类型。当需求下降时(例如在周末),我们为闲置的虚拟机付费。
唯一比机器闲置更糟糕的是,我们的工程师不得不拼命工作,以跟上不断变化的需求。机器团队的高级 Fullstack 工程师 John Swanson 解释说:“池的大小是固定的,但任务到达的速度是变化的。"任何排队的迹象都会引来呼叫工程师."虽然保持高可用性和低排队时间对我们来说很重要,但我们也意识到我们需要一种方法来减少工程团队的体力劳动,将他们的能力释放出来从事更高价值的工作。我们如何构建一个可以根据客户需求伸缩的系统?
“我们假设这将是一个非常复杂的公式,”盖修继续说道。“我们都离开了,开始研究。(我们的一个同事)马克回来后说,“我们为什么不试试这个简单的公式?”…实际上效果非常好。"
使用经典的排队论,以及从我们的 VM 服务中收集的数据,该团队能够将样本数据插入到电子表格中不同的排队论模型中。我们很想知道不同的模型会产生什么:每个模型需要预启动多少个虚拟机?
事实证明,排队经验法则在预测我们手动配置 VM scaler 时已经拥有的值方面做了令人难以置信的工作。这给了我们信心去尝试增量应用它。从今年 8 月开始,我们就这样做了。
很快,我们看到高峰时间的排队时间从 3 分钟减少到不到一分钟,非高峰时间的空闲机器也减少了。我们慢慢地将我们的系统从手动扩展过渡到自动扩展,高峰等待时间减少了 60%,并且更加接近非高峰时间的等待时间。
同时,引入自动扩展使我们能够将维护平台上每个资源类所需的工作量从 1 小时/月/资源显著减少到零。通过这样做,我们能够将工程师的时间解放出来,专注于其他工作。
客户开始报告更加一致的工作开始时间,无论是一天中的时间还是一周中的时间。但更重要的是,自动化扩展让我们大大扩展了可供客户使用的资源类型目录。
“以前,分配正确数量的机器需要不断更新每一对图像到资源,”机器团队的产品经理 Alexey Klochay 解释说。“随着我们提供的[机器类型和资源类别]数量的增加,团队的负担也在增加。因此,我们投资于团队效率,这为更多样的客户使用情形带来了更多选择。”举个具体的例子,我们新的 autoscaler 允许我们在更短的时间内发布最新的资源类,包括窗口。
-
要了解更多关于我们的自动缩放器的构建,请听听高级员工工程师(也是那个说“让我们试试排队论”的家伙)Marc O'Morain 在 TheREPL 播客上的发言。
-
关于智能 CI/CD 的更多信息,请了解 CircleCI 的自动测试分割。
带 CircleCI 的智能 CI/CD:测试拆分- CircleCI
原文:https://circleci.com/blog/intelligent-ci-cd-with-circleci-test-splitting/
在 CircleCI,我们的团队每天都在努力为工程生产力构建最佳的高性能平台。有一些我们熟知的功能:工作流、orb 和一流的 Docker 支持。但 CircleCI 团队也在幕后努力优化,以使软件开发更快、更智能、更安全——我们意识到我们的客户可能不知道这些方式。为此,我们想带您了解我们平台的一些鲜为人知的方面。我们将向您展示它们是做什么的,它们是如何工作的,并为您提供让 CircleCI 的内置智能为您工作的提示。今天的帖子是关于测试分裂的。
速度和利润的智能测试拆分
对开发人员效率最重要的贡献之一是开发人员是否能尽快得到他们需要的信息——测试结果可能是最重要的。开发人员花在等待测试运行上的任何时间都不是花在编写下一段代码上的时间,更不用说等待和失去他们正在工作的上下文的成本了。快速反馈就是一切。
您知道 CircleCI 可以智能拆分测试以更快地获得您的测试结果吗?
测试和测试套件的长度变化很大。如果您天真地将测试拆分成不同的任务,您可能会花费大量的时间等待,因为您需要等到组中的最后一个任务完成后才能继续。出于这个原因,测试拆分非常重要。
CircleCI 具有内置的平台智能,可以根据您的并行性水平将您的长测试和短测试分组在一起,以最大限度地减少您的测试套件的总时间。我们挖掘您跑步的历史持续时间数据,以优化最短的可能套件。现在,我们的性能计划中的客户可以从测试分割中获得更多,因为他们不受容器的限制:他们可以同时运行 10、20 甚至 40 个测试分组,而不必为访问 40 个容器付费。
让我们看一个例子。假设您有一个单元测试工作和一系列集成测试。您已经设置了您的工作流,以便当该作业完成时,集成测试作业以 10 倍的并行度运行。这些包括一些运行时间长得多的测试,因为它们包括启动浏览器或与数据库对话等步骤。如果您天真地将它们分割成每个容器相同数量的测试,那么您很容易就会陷入这样一种情况:您有许多完成的工作单元(例如,因为它们每个都花了一分钟),并且一个任务必须运行 10 倍长的时间,因为您碰巧将最长的测试组合到一个任务中。相反,如果你把这些按时间展开,整个单位的工作现在需要接近 1 分钟,而不是 10 分钟。
有了这个改变,你的测试套件就增加了 10 倍。
我们还可以分享 CircleCI 测试套件中的一个真实例子。这里有一组测试,分组在相同测试号(但测试长度不同)的簇中,随机分布在 10 个容器中。该图中的每个条形代表一组随机的测试:
下面是这些相同的测试,根据我们的历史运行数据重新分组,以优化相似的运行时间:
在随机分布的情况下,最快的一组测试记录为 107 秒,最慢的为 219 秒。
启用智能测试分割后,最快的分组达到了 116 秒,但最慢的却飙升到了 173 秒。
这意味着总的来说,我们已经将传播从 184 秒减少到 57 秒。
并且:CircleCI 可以自动为你做到这一点。当您启用测试分割时,CircleCI 将不断动态地重新平衡您的测试分割,以最大限度地减少您等待结果所花费的时间。
如何充分利用测试拆分
CircleCI 自动从您的测试文件中为您拆分测试。但是在你的控制范围内有一些事情可以优化你的测试分割:
-
启用 CircleCI 的测试元数据集合以启用测试拆分。几乎所有的测试框架都允许您将测试结果输出到一组 XML 文件或 cumber JSON 文件中。如果您的套件可以生成这些文件类型,我们将解析这些结果(例如:您运行了多少次测试,失败了多少次),并使用计时数据来优化未来的运行。此外,您还将获得额外的特性,比如 CircleCI UI 中的格式化故障数据。关于从你的测试数据中扩展洞察力的例子,请看这篇博文。
-
打开定时数据分割。我们所有的测试分割方法在任务间动态地自动分配你的测试。按时间划分是我们优化测试结构的最明智的方法,以最快的速度通过测试(阅读这篇博文中 Amio 团队使用 Gradle 设置测试的例子)。一旦您启用了按时间划分,CircleCI 将从以前的运行中查找时间数据,并预测运行每个测试需要多长时间,然后分配测试以最小化获得结果所需的总时间。
-
不要编写依赖于排序的测试。这是一个超越自动测试分割的最佳实践。结构良好的测试是相互独立的。不推荐编写跨测试的依赖关系,因为这会妨碍您利用并行性或重新排序。
-
保持你的测试文件小而有条理。相反,进行有用的测试分组。保持它们较小,以便我们可以根据需要调整它们来优化您的测试。小工作单元是组织和优化的关键。例如,对于 Rails 或 Ruby 测试文件,CircleCI 会对文件进行重新排序,但不会对这些文件中的测试进行重新排序。如果所有内容都在一个文件中,我们就无法对您的套件进行太多优化。此外,一个大的单个测试文件可能表明代码组织得同样糟糕。如果你不能分割它们,你的代码文件太大了。
-
优化您的测试以节约成本。在 CircleCI,我们会竭尽全力尽快为您提供反馈和测试结果。但是请记住,您可以通过将更多的测试覆盖推向更简单的测试来减少总花费的时间,比如单元测试,这样运行起来更便宜更快。一旦你做到了这一点,CircleCI 仍然可以并行化这些测试,总体时间的减少将会带来回报。想了解更多关于经济测试的背景信息,请看这篇博文。
出于好奇:我们为什么要建造这个?
我们最初在 CircleCI 1.0 中构建了测试计时。在 CircleCI 的早期版本中,所有并行任务都是同步运行的。因此,当测试阶段开始时,直到上一步的所有并行任务完成后才开始。然后,测试阶段将会运行。如果你有 10 个容器,即使 9 个容器已经完成了,只要最后一个容器还在测试中,你也有可能支付 10 个容器的时间。
你可以想象,这并不理想。当我们最初构建智能测试分割时,是为了节省客户的资金,并优化他们已经分配的容量的使用。这也节省了时间,减少了价值交付的关键路径。现在有了 CircleCI 2.0,所有的任务都是独立的,因此不再需要为你没有使用的资源付费。如果您的某项任务完成,我们会将该容量返还给虚拟机池,这样您就不会被收费。虽然从成本角度来看,这种方法肯定是一种改进,但是长期运行的任务仍然会阻碍开发人员获得结果。所以测试分割仍然是尽快获得开发人员反馈的好方法。
解决长时间运行的问题不仅仅是拥有快速的计算机,而是以一种尽可能快地获得结果的方式优化所有资源。
我们为 CircleCI 的智能自动优化更加努力地帮助您充分利用 CI/CD 管道而感到自豪。请关注 CircleCI 使用数据和智能从您的构建中获取更多价值的其他方式,这将在本系列的剩余部分中很快推出。
以局外人的身份采访:我是如何最终被技术圈看到的
原文:https://circleci.com/blog/interviewing-as-an-outsider-how-i-finally-got-seen-in-tech/
进入科技世界对我来说并不容易。我在东巴尔的摩长大;我知道这个系统有多不公平。人们经常谈论科技的多样性。在我看来,他们认为多样性只是表面现象,但我相信它远不止于此。例如,我在科技界认识的大多数其他非裔美国人都来自父母双全的家庭,都上过非常好的学校;我从小和单亲妈妈一起长大,上的是社区大学。当我完成了所有的 CS 核心课程后,我就退学了,这样我就可以开始工作了。硅谷的人从精英学校辍学时会受到钦佩,但如果你没有从斯坦福辍学,就不会受到祝贺。这完全取决于你的人口统计情况。
当我来到旧金山开始找工作时,我觉得好像没有人和我一样。面试非常困难。在我参加面试之前,我会对面试我的人做一些调查,这样我就能找到一些共同话题。但是对于我在采访中遇到的人,我常常找不到一点我们的共同点。我听到人们编造关于我的故事,说我是“来自巴尔的摩自学编程的工程师。”这不是真的:我受过传统训练。我希望我能说我自学的。我想成为善意的猎手。我想人们需要告诉自己。
我经历的很多面试过程都让人感觉相当冷淡;感觉他们并没有表现出太多的关心。我甚至不在乎我这个人。在我看来,技术面试过程是评估一个人编写软件能力的糟糕方式。在面试的时候,我会遇到一些问题,比如你可以在破解代码面试中找到的关于图形算法的问题。它告诉我,他们不在乎他们采访的人,因为他们必须给每个人同样的采访。如果我只解决了抽象的学术问题就通过了你的面试,你对我的了解就是我是一个能读那本书的人。任何人都可以一字不差地做事。成为一个优秀团队的一部分还需要更多的技能:比如你与他人合作得有多好,以及你愿意为解决一个真正的问题付出多少努力。
尽管我很想要一份工作,但在我面试的大部分时间里,我都持消极态度,因为我知道自己不适合这些公司中的大多数。他们试图说服我,因为他们拥有大型科技公司的顶尖人才。但那并没有打动我。我不在乎任何人来自哪里;我想和真正想一起做事的人一起工作。告诉我人们来自哪里并不能告诉我一个公司的文化。它告诉我的是,比起人们真正带来的东西,人们更关心凭证。信任、忠诚和诚实是我来自的社区的价值观,我在这里的文化中认识到了这一点。只要你拥有这些东西,你就拥有了一个强大的家庭,这个家庭会为了实现一个目标而一起努力。
当我在 CircleCI 的面试过程开始时,我知道我已经找到了正确的地方。Lev Lazinskiy(我们的发布经理)是我第一次就技术筛选与他交谈的第一人。我准备了五分钟的“告诉我关于你自己的情况”,这甚至没有发生。Lev 已经知道了我的名字,并对我的经历做了一些研究。他花时间问我关于编程范例的哲学问题,关于我对 Linux 系统的熟悉程度的问题。这是第一次感觉不像被欺负。通常会有一些关于快速排序的运行时间的问题,或者关于我将使用什么算法来创建一个图书馆图书跟踪系统(回答:我会使用一个关联数组。咄)。Lev 对我非常尊重,让我觉得他们只是在寻找合适的技能来完成工作,而不是让我通过一系列预演的脑筋急转弯。
我一到 CircleCI 就注意到员工的一件事,那就是我们不仅仅雇佣斯坦福、哈佛和伯克利毕业的人。这里的人们来自各行各业,这已经表明我们看重人们的技能而不是他们的出身。我到这里的第一天,我注意到办公室里的一些人非常聪明。每个人看起来都不整齐划一,但都很恭敬。这不是一个有着狂热文化的普通创业公司。这里的每一个人都是建立在互相激励的基础上,让他们在努力中走得更远。我看到很多人互相帮助建立关系。Eugene 和 Hannah 参加了相同的 Coursera 课程,并互相学习新技能。贾斯汀让我重新开始健身,重新打篮球。安东一直在帮我学习 Clojure。我非常尊重他,我认为认识其他思考个人发展的人总是很酷。这是我工作过的第一个员工之间没有摩擦的地方;这是一个非常成人化的环境,在这里人们掌握主动权,并着手实现他们的目标。
这家公司看重努力工作的人,而不是简历令人印象深刻的人。最终,如果你有热情的员工,你将有一个足够强大的团队来保持软件生命周期。并非每个人都来自典型的背景,但他们都对公司充满热情。汉娜没有去学计算机科学,但她是这里最努力工作的人之一。泰德也是自学成才的,他很努力。很多地方雇佣有好技能的人,但是我认为如果你没有充满激情的人,那么软件会很烂。我的意思是…如果我不喜欢我所在的篮球队,我就不会在乎防守球场。
数据库测试介绍| CircleCI
在软件开发中,以不同状态处理和存储数据反映了应用程序所基于的业务规则。任何软件应用程序的核心和灵魂都是保存在数据库中以供检索和进一步处理的数据。为应用程序选择的数据库系统(SQL 或非 SQL)必须满足应用程序所需的数据处理和存储需求。有什么比建立一个系统来测试数据库以确定其能力更好的方法呢?
什么是数据库测试?
我们已经看了测试代码以及如何正确地测试 API,但是我们应用程序的数据层呢?数据库测试是什么?
数据库测试主要包括构建 SQL 查询来断言和验证数据库应用程序所需的不同数据库操作、结构和属性。
这个过程可能包括验证模式、测试 CRUD 操作和事务,以确保数据库设置正确。这些测试可以是全自动的、全手动的,或者是混合使用手动和自动过程的混合方法。例如,在一个完全手工的测试中,您可以进入数据库管理系统并运行查询来验证假设。或者,您可以测试应用程序 UI,看它在操作后返回正确的数据。
数据库测试人员与应用程序开发人员一起工作,正确测试数据库运行的场景。除了熟悉数据库结构之外,数据库测试人员还应该完全理解应用程序的业务规则。
为什么数据库测试很重要?
当应用程序中的数据完整性遭到破坏时,可能会导致巨大的经济损失,进而导致整个企业的崩溃。这些后果的严重性从对数据不太敏感的特性(如一条推文的转发次数)到交易应用程序中股票的实际价值不等。虽然数据库测试不能防止所有的数据泄露或完整性损害,但通过彻底测试用于应用程序的数据库系统,可以减轻最坏的后果。
测试数据库的一些常见原因是:
- 防止攻击,如 SQL 注入攻击
- 确保网络问题或断电不会影响数据的完整性或导致数据丢失或损坏
- 从数据库中删除错误以保持数据质量
- 验证每一条数据都以正确的格式存储
- 验证数据库中实体之间的关系
和所以更多。
应该考什么?
一旦你理解了数据库测试是什么以及它为什么重要,你就可以应用你所知道的来确保所有的测试用例都被很好的覆盖。
create, read, update, and delete
第一组测试用例用于应用程序执行的创建、读取、更新和删除(CRUD)操作。这是为了确保以保证数据完整性的方式存储和检索数据。测试人员可以直接从应用程序界面完成这项工作,或者使用数据库管理系统(DBMS)通过 SQL 数据操作语言(DML)命令运行查询。可以破坏数据库中数据的恶意 SQL 命令也可以在测试环境中运行,以确保数据库免受 SQL 注入攻击。
处理
事务是敏感的数据库操作,因为它们需要执行不同的查询,并从故障中正确恢复。标准的数据库事务遵循 ACID 原则。
- 原子的:它必须完成所有的操作或者不执行任何操作
- 一致:数据库的状态必须始终有效,并且必须遵守所有约束
- 隔离:每个事务必须与同时运行的其他事务隔离执行。最终的数据库状态必须是事务按顺序运行
- 持久性:一旦提交事务,不会因为任何原因丢失数据
数据库测试人员创建 SQL 查询来检查和验证应用程序中事务操作的这些属性。这种测试在测试金融应用程序时尤其重要。
(计划或理论的)纲要
数据库模式是数据库结构的蓝图,测试人员需要非常熟悉它。测试人员可以使用 SQL describe ( DESC
)命令来揭示数据库模式,以确保它符合应用程序的期望。测试人员还使用正则表达式来验证表字段名称,并验证该值是否符合预期的数据类型。
扳机
触发器就像代码中的事件处理程序。当在表上发生操作时(例如,当添加新行时),可以设置触发器来执行一段代码或查询,以响应刚刚发生的操作。触发器会对某些操作产生级联效应。例如,从数据库中删除用户也可以触发用户的帖子被删除。作为测试人员,您希望确保该操作准确发生,而不是删除其他用户的帖子。
测试人员可以运行 SQL 查询来启动触发级联的原始操作。测试人员也可以从应用程序的界面执行操作,以检查它对数据库记录的影响。
其他人
我前面描述的操作并不是唯一可以测试的操作集,它们只是大多数数据敏感应用程序中最重要的一部分。
其他可以测试的操作和属性有:
- 数据库约束
- 存储过程
- 视图
- 指数
如何测试数据库
现在我们知道了要测试什么,我们应该如何执行测试呢?令人惊讶的是,运行数据库测试与运行应用程序测试并没有太大的不同。
正如我前面提到的,这些测试可以通过从应用程序 UI 执行操作来手动执行,以确保每次操作后都返回正确的数据,或者通过检查数据库记录来获得操作的结果。您还可以使用一个 DBMS 来运行您的测试查询并验证结果。
如果您不愿意手动测试,那么您可能会放心,因为自动化数据库测试与应用程序代码的自动化测试非常相似。主要的区别在于,这一次,您的测试运行的是查询,而不是应用程序代码。测试应用程序代码中的以下步骤也适用:
- 准备您的测试环境
- 使用测试运行器运行您的测试(例如 Selenium )
- 检查并验证您的结果
- 报告你的主张
这就是为什么数据库测试人员最好的属性是能够为每个需要的测试用例设计 SQL 查询。
数据库测试工具
有很多数据库测试工具。您选择的数据库测试工具将取决于以下一个或多个因素:
- 测试策略(手动、自动或混合)
- 数据库类型(SQL 或非 SQL)
- 数据库供应商(MySQL、MSSQL、Oracle 或其他)
大多数数据库测试系统不仅仅由一个工具组成。例如,Selenium 可以与 TestNG 一起用于 Java 应用程序中的数据库测试。类似地, SeLite 使用 Selenium 测试 SQLite 数据库,而 SQL Server 捆绑了用于单元测试数据库的工具。
你可以在这里找到一个数据库测试工具的列表。根据前面列出的因素做出选择。
结论
数据库测试是确保应用程序可靠性的另一个测试驱动的开发过程。数据是所有应用程序的核心,确保用户能够信任您的应用程序始于正确获取数据。
编码快乐!
Fikayo Adepoju 是 LinkedIn Learning(Lynda.com)的作者、全栈开发人员、技术作者和技术内容创建者,精通 Web 和移动技术以及 DevOps,拥有 10 多年开发可扩展分布式应用程序的经验。他为 CircleCI、Twilio、Auth0 和 New Stack 博客撰写了 40 多篇文章,并且在他的个人媒体页面上,他喜欢与尽可能多的从中受益的开发人员分享他的知识。你也可以在 Udemy 上查看他的视频课程。
使用软件测试生命周期| CircleCI 为应用程序增值
原文:https://circleci.com/blog/intro-to-software-testing-life-cycle/
本教程涵盖:
- 使用示例应用程序作为测试案例研究
- 软件测试生命周期概述
- 软件测试生命周期阶段 1 到 6
软件测试非常重要,在软件开发生命周期(SDLC)中有它自己的阶段。软件测试生命周期(STLC) 是一个循序渐进的过程,通过对测试过程进行严格的规划和分析来提高软件质量。
测试是一种开发工具,可以为您的开发团队的应用程序增加价值。将测试作为软件开发的一个重要组成部分,可以为您和您的团队在将来调试和修复错误时节省大量时间。在这篇文章中,我将通过描述每个步骤以及它如何帮助您的团队在整个开发生命周期中正确地测试软件,来带领您经历软件测试生命周期的各个阶段。
https://www.youtube.com/embed/sTLZDNQq5C4
视频
先决条件
在创建本教程时,已经做了一些假设:
- 您是一名开发人员、测试人员、产品经理,或者参与了软件开发生命周期的任何阶段
- 您对部署可靠的应用程序感兴趣
- 您认为良好的用户体验对于软件应用的成功至关重要
我们的教程是平台无关的,但是使用 CircleCI 作为例子。如果你没有 CircleCI 账号,请在 注册一个免费的 。
使用示例应用程序作为测试案例研究
为了帮助您理解组成测试每个阶段的活动,我创建了一个示例应用程序。我将使用示例应用程序作为案例研究,指导您完成每个阶段的步骤。对于示例,我选择了任何应用程序最常见的用例之一。几乎每个访问过网站的人都必须用他们的凭证登录。因此,首先使用示例应用程序测试用 HTML、CSS 和 JavaScript 构建的登录流程。
以下是步骤:
- 打开登录页面
- 输入电子邮件和密码
- 单击按钮登录
如果凭证正确,将向用户显示他们的配置文件。如果它们不正确,则向用户显示一条错误消息。
理解软件测试生命周期的各个阶段
既然您已经选择了想要测试的功能,那么就开始将 STLC 应用到您的应用程序中。软件测试生命周期有六个阶段:
- 需求分析
- 计划测试
- 开发测试用例
- 设置测试环境
- 测试执行
- 测试结束
在本教程中,我将解释如何按照这六个步骤测试您的登录流程。
软件测试生命周期阶段 1 -需求分析
在这个阶段,质量保证团队与所有利益相关者会面,以全面了解应用程序的需求。对应用程序应该如何运行的全面了解允许您判断测试过程的范围。需求可以是功能性的或者非功能性的。花一些时间对特性和功能进行优先排序,以细化测试的重点,避免在对利益相关者(包括用户)不太重要的事情上浪费时间。
同样在这个阶段,确定您将使用什么类型的测试环境设置,以及您是否能够自动化测试。
对于应用程序登录流程,分析应用程序需求将确定:
- 登录应用程序时要访问的 URL
- 登录表单上会显示什么信息
- 登录应用程序所需的凭据
- 预期登录的用户类型
- 具有互联网连接的每个人都可以登录,还是仅限于某个地理区域
- 内置应用程序的基本代码的类型
- 具有我们代码库的应用程序需要的测试环境
- 是否有任何登录凭据是可选的
- 向用户显示的错误和成功消息
- 测试是否可以自动化
甚至对于我们有限的样本用例来说,还有更多的可能性。在这个阶段结束时,您的团队应该有一份详细的需求文档。
软件测试生命周期阶段 2——计划测试
当需求分析阶段完成时,是时候继续计划您的测试了。在这个阶段,测试团队经理估计测试过程中的成本和工作量。评估包括所需的资源、工具和测试环境。还确定了测试或资源的限制。
测试计划阶段的另一部分是为涉及的活动和人员创建测试时间表。规划阶段的目标是有一个包含测试策略、详细计划和时间表的工作文档。
示例应用程序中登录功能的规划可能包括:
- 确定执行测试所需的开发人员和测试人员的数量
- 设置和运行测试所需的时间
- 测试环境的工具;Jest 和木偶师只是两个例子
- 测试的系统要求,包括对应用程序不支持的旧版本软件的限制
- 基于前一测试阶段分析的需求的测试用例列表
测试计划中可能包含更多的活动和考虑事项。
软件测试生命周期阶段 3——开发测试用例
当您的测试计划和日程安排就绪时,团队就该开始开发详细的测试用例了。开发测试用例包括识别它需要的特定测试数据。
示例应用程序的测试用例开发活动可以包括:
- 定义成功的登录案例,包括标准和用户凭证
- 当没有提供凭证时,设计失败的登录流
- 设计当用户输入不完整的凭证时登录失败的情况,并确定这些凭证是什么
- 设计当用户输入不正确的凭证时登录失败的情况,并确定凭证是什么
- 创建测试用例和自动化脚本
当然,这只是您在测试生命周期的这个阶段可能完成的活动的一个例子。
软件测试生命周期阶段 4 -设置测试环境
到目前为止,测试生命周期的每个阶段都依赖于前一个阶段。幸运的是,这个阶段可以与测试用例开发阶段同时完成。设计好测试环境需求之后,您就可以开始设置测试环境了。
测试环境应该尽可能模拟软件在生产环境中运行的条件。开发人员或测试人员都可以建立测试环境;这里不需要测试团队。
设置测试环境的一些活动包括:
- 按照生产中使用的最低要求设置操作系统环境
- 建立测试框架;比如 Jest 或者摩卡
- 设置测试转轮;类似于因果报应或者笑话的东西
- 建立断言库,如 Chai.js
- 创建测试数据、模拟库和资产
- 为浏览器测试安装支持的浏览器
而且,你猜对了,更多。
软件测试生命周期阶段 5 -测试执行
随着测试用例的开发和测试环境的建立,测试人员可以开始执行测试脚本。随着测试用例的执行,结果被编译,错误被报告给测试团队,用于文档化和测试用例细化。
有时需要重新测试。例如,测试团队可能会在一个或多个测试用例的设计中发现一些缺陷,或者有人可能会发现需要额外的测试用例。
软件测试生命周期阶段 6 -测试结束
在执行测试、重新测试(如果需要的话)、识别 bug 并记录测试结果之后,是时候结束测试生命周期了。在此阶段,将结果汇编成结构化报告,供风险承担者评估。确保测试团队开会分析测试结果和工件。花一些时间确定可以对测试策略进行的改进。使用时间、成本、测试覆盖范围以及与业务期望的一致性等标准来衡量这个测试周期的成功。
这一阶段的输出是一份详细的测试结束报告,其中包括有意义的、易于理解的测试指标。使用这些指标来确定在这个测试周期中取得的成功程度。
结论
彻底和专业的软件测试生命周期是为您的团队创建质量文化的最佳方式。作为奖励,这种“质量文化”将开始为您的利益相关者建立对您的软件应用程序的信心。通过仔细研究错误来消除缺陷,可以让您的团队更加深入地了解您的应用程序是如何工作的,这可以在开发下一个版本时节省时间。在一个程序中找到所有的错误是不切实际的,所以详尽、广泛的测试不是最好的目标。每个测试人员和开发人员的目标应该是找到并修复对应用程序的使用和性能有最大负面影响的错误。
编码快乐!
Fikayo Adepoju 是 LinkedIn Learning(Lynda.com)的作者、全栈开发人员、技术作者和技术内容创建者,精通 Web 和移动技术以及 DevOps,拥有 10 多年开发可扩展分布式应用程序的经验。他为 CircleCI、Twilio、Auth0 和 New Stack 博客撰写了 40 多篇文章,并且在他的个人媒体页面上,他喜欢与尽可能多的从中受益的开发人员分享他的知识。你也可以在 Udemy 上查看他的视频课程。