在我参加AWS re:invent和KubeCon等行业活动的互动中,我与很多开发者交谈。开发人员经常讲述一些阻碍他们快速有效工作的事情。许多故事涉及与系统管理员、SRE或DevOps同事之间令人沮丧的互动。有一个故事我已经听过好几次了,涉及到这样的对话。
dev: 嘿,SRE团队。我的构建失败了,我不知道构建节点中的应用发生了什么。它在CI/CD平台上失败了,但构建脚本在我的开发者环境中工作正常。我可以在平台上对构建节点进行SSH访问吗,这样我就可以实时调试了?
SRE。 一小时后如何?
dev: 一小时?我需要完成这个,这样我就可以开始为下一个版本的新功能做黑客了。你能给我访问构建节点的权限吗,这样我就能在构建失败的实际资源上进行调试?
SRE。 我们的CI/CD平台没有SSH权限,给你我的管理凭证是违反安全的。
有时对话会继续。
dev: 那我们安装的SSH插件呢?这让我们可以向构建者节点发送控制台命令,这样我们就可以在系统日志中捕获响应。
SRE。 安全部将其标记为CVE-2017-2648的弱点,可以进行中间人攻击。安全部禁止在我们的CI/CD平台中使用它。我们没有进入节点的SSH功能,无法帮助你进行实时调试。对不起。
它以开发者的思维结束。
dev: 如果我只使用单元测试和堆栈跟踪记录,那么我将会花很长时间来调试这个构建。我还不如去猜测。
虽然这段对话是一种概括,但它是基于我在职业生涯中经历的和在活动中听到的真实的互动和情况。这是很常见的场景,大多数团队都会经历类似的情况。
当我从CircleCI用户那里听到这个故事时,我为他们提供了一个很好的解决方案:一个有用的和强大的SSH调试功能。这个功能可以让开发人员在构建失败的资源上进行故障排除和调试。让我告诉你它是如何工作的。
访问流水线作业
在开发者正常开发环境之外的资源和环境中调试代码,会带来挑战,消耗宝贵的时间。如果没有使开发人员能够访问和排除失败的构建的功能,CI/CD平台本身就成为开发人员和SRE团队的一个巨大障碍。由于没有对构建节点的SSH访问,开发人员不得不在构建失败的CI/CD环境之外调试失败的构建。他们不得不尝试在他们的开发环境中复制CI/CD环境,以准确地识别问题,然后试图只使用应用程序、堆栈跟踪和系统日志来解决这个问题。这些类型的情况对每个人来说都是一种巨大的时间浪费。
SSH调试允许开发人员轻松和安全地在发生故障的资源上实时调试他们失败的构建。通过CircleCI,SSH调试也为开发人员提供了自我服务机制,以安全地访问构建环境,而不必依赖其他团队。这对开发人员和运营团队来说都是一个巨大的时间节省。
排除一个失败的流水线作业的故障
当你使用CircleCI时,用SSH访问构建作业很容易。我将通过一个常见的构建失败场景来展示如何排除一个失败的构建作业的故障。这里有一个样本config.yml ,供我们在这种情况下使用。
version: 2.1
workflows:
build_test_deploy:
jobs:
- build_test
- deploy:
requires:
- build_test
jobs:
build_test:
docker:
- image: cimg/python:3.10.0
steps:
- checkout
- run:
name: Install Python Dependencies
command: |
pip install --user --no-cache-dir -r requirements.txt
- run:
name: Run Tests
command: |
python test_hello_world.py
deploy:
docker:
- image: cimg/python:3.10.0
steps:
- checkout
- setup_remote_docker:
docker_layer_caching: false
- run:
name: Build and push Docker image
command: |
pip install --user --no-cache-dir -r requirements.txt
~/.local/bin/pyinstaller -F hello_world.py
echo 'export TAG=0.1.${CIRCLE_BUILD_NUM}' >> $BASH_ENV
echo 'export IMAGE_NAME=python-cicd-workshop' >> $BASH_ENV
source $BASH_ENV
docker build -t $DOCKER_LOGIN/$IMAGE_NAME -t $DOCKER_LOGIN/$IMAGE_NAME:$TAG .
echo $DOCKER_PWD | docker login -u $DOCKER_LOGIN --password-stdin
docker push $DOCKER_LOGIN/$IMAGE_NAME
该样本config.yml ,指定了一个2个作业的工作流管道,测试代码,基于应用程序构建Docker镜像,并将该镜像发布到Docker Hub。为了将新镜像发布到Docker Hub,该工作需要Docker Hub凭证。这些证书是高度敏感的,在$DOCKER_LOGIN 和$DOCKER_PWD 安全环境变量中安全地表示。这些变量被设置为项目级环境变量。如果$DOCKER_LOGIN 和$DOCKER_PWD 环境变量在项目层面上不存在,这个构建将在构建和推送Docker镜像步骤中失败。
识别我们失败的作业

失败的工作日志显示,失败发生在Docker构建过程的开始阶段,如这个日志条目所示。
invalid argument "/python-cicd-workshop" for "-t, --tag" flag: invalid reference format
See 'docker build --help'.
Exited with code 125
现在我们知道了管道中哪里出现了故障,我们可以通过SSH访问轻松地重新运行这个失败的构建。当用SSH访问重新运行作业时,管道将再次运行并失败,就像以前一样。但这一次,运行时节点会保持活跃,并向用户提供如何访问失败的构建资源的详细信息。
用SSH重新运行作业
为了获得SSH访问失败的构建,从CircleCI仪表板中重新运行失败的作业。
- 登录到CircleCI的仪表板
- 点击失败的作业
- 点击仪表板右上方的向下按钮,然后选择用SSH重新运行作业

这张图片显示了一个例子,开发人员必须使用SSH访问资源的访问细节。

SSH访问细节在构建结束时提供。
ssh -p 64535 100.27.19.200
访问构建环境
现在我们有了SSH访问构建环境的权限,我们可以对我们的构建进行故障排除。如前所述,日志条目表明,这个问题与我们部署步骤中的Docker构建部分有关。错误信息的invalid argument "/python-cicd-workshop" 部分向我显示,Docker用户名在"/python-cicd-workshop" 。
Docker镜像名称是在config.yml 文件的这一行定义的,由环境变量组成。
docker build -t $DOCKER_LOGIN/$IMAGE_NAME -t $DOCKER_LOGIN/$IMAGE_NAME:$TAG .
我们知道,Docker镜像构建失败是因为镜像名称不合适,而且我们知道这个名称是由环境变量组成的。这表明失败与不正确或不存在的环境变量有关。打开一个终端,SSH进入构建环境。我们想运行一个命令来测试我们关于环境变量的假设是否正确。
$ printenv |grep DOCKER_LOGIN
printenv |grep DOCKER_LOGIN 命令告诉系统显示$DOCKER_LOGIN 环境变量和它的值。这个命令的输出将告诉我们,$DOCKER_LOGIN 这个变量是否被设置。如果该命令没有返回一个值,那么我们就知道系统在初始执行构建时没有设置$DOCKER_LOGIN 这个变量。在这种情况下,没有返回值。这就是导致我们失败的原因。
修复构建
现在我们已经验证了我们缺少$DOCKER_LOGIN 这个环境变量。我们可以通过使用CircleCI仪表板在项目中添加缺少的$DOCKER_LOGIN 和$DOCKER_PWD 变量来修复构建。由于这些变量的值是非常敏感的,它们必须被定义并安全地存储在CircleCI平台上。您可以通过以下说明来设置这些变量。
- 在CircleCI仪表板的左侧菜单中点击添加项目
- 在项目列表中找到并点击项目的名称,点击设置项目
- 在CircleCI仪表板的右上方区域点击项目齿轮
- 在构建设置部分,点击环境变量
- 点击添加变量
在Add an Environment Variable 对话框中,定义本次构建所需的环境变量。
- 姓名:。
DOCKER_LOGIN值。Your Docker Hub User Name - 名称: 值
DOCKER_PWD值。Your Docker Hub Password
正确设置这些环境变量是成功完成构建的关键。
重新运行构建
现在,我们已经为我们的构建设置了所需的环境变量,我们可以重新运行失败的构建,以测试我们的变化是否有效。进入CircleCI仪表板,点击Rerun from Beginning,启动项目的重建。等待你的构建成功完成。

总结
在这篇文章中,我强调了CI/CD管道的SSH调试的必要性。我展示了CircleCI的SSH功能的力量,以及任何用户如何安全和容易地访问他们的构建环境,并实时调试失败的构建。这个功能使开发人员能够快速识别和修复他们的错误构建,从而使他们能够集中时间和注意力来构建用户需要的新的和创新的功能。