基于Docker托管Azure DevOps代理
Posted dotNET跨平台
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于Docker托管Azure DevOps代理相关的知识,希望对你有一定的参考价值。
Azure DevOps非常好用,但是为代理准备单独的服务器经常会显得性价比不高:配置低了,前端构建时会教会你做人,配置太高又有点浪费资源,代理数量少了各团队构建要打架。对于既想享受DevOps的美妙之处但是资源捉襟见肘的小公司,真是一件比较头痛的事情。那么有没有更具备性价比的方案呢?那自然是有的,那就是基于Docker进行自托管。
这里不建议大家丢k8s集群里面去,一是会抢资源,二是k8s容器运行时不推荐大家使用docker,三是不安全。那么现在我们就可以准备一台好点的服务器,来基于Docker来托管自有的Azure DevOps代理。
编写Dockerfile
废话不多,建议大家直接抄代码吧:
FROM ubuntu:20.04
RUN DEBIAN_FRONTEND=noninteractive apt-get update
RUN DEBIAN_FRONTEND=noninteractive apt-get upgrade -y
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends \\
apt-transport-https \\
apt-utils \\
ca-certificates \\
curl \\
git \\
iputils-ping \\
jq \\
lsb-release \\
software-properties-common \\
gss-ntlmssp
RUN curl -sL https://aka.ms/InstallAzureCLIDeb | bash
# Can be 'linux-x64', 'linux-arm64', 'linux-arm', 'rhel.6-x64'.
ENV TARGETARCH=linux-x64
WORKDIR /azp
COPY ./start.sh .
COPY ./vsts-agent-linux-x64-2.181.2.tar.gz .
RUN chmod +x start.sh
ENTRYPOINT [ "./start.sh" ]
如果对Dockerfile不理解,可以参考笔者之前的教程、博客和书籍《Docker+Kubernetes应用开发与快速上云》来解决问题以及查看日志。这里不建议大家使用官方教程,基本上走不通还问题颇多。
值得注意的是,上面涉及到了两个文件:
start.sh
vsts-agent-linux-x64-2.181.2.tar.gz(从Azure DevOps管理界面下载)
start.sh脚本内容参考如下:
#!/bin/bash
set -e
if [ -z "$AZP_URL" ]; then
echo 1>&2 "error: missing AZP_URL environment variable"
exit 1
fi
if [ -z "$AZP_TOKEN_FILE" ]; then
if [ -z "$AZP_TOKEN" ]; then
echo 1>&2 "error: missing AZP_TOKEN environment variable"
exit 1
fi
AZP_TOKEN_FILE=/azp/.token
echo -n $AZP_TOKEN > "$AZP_TOKEN_FILE"
fi
unset AZP_TOKEN
if [ -n "$AZP_WORK" ]; then
mkdir -p "$AZP_WORK"
fi
export AGENT_ALLOW_RUNASROOT="1"
cleanup()
if [ -e config.sh ]; then
print_header "Cleanup. Removing Azure Pipelines agent..."
# If the agent has some running jobs, the configuration removal process will fail.
# So, give it some time to finish the job.
while true; do
./config.sh remove --unattended --auth negotiate --userName build --password $(cat "$AZP_TOKEN_FILE") && break
echo "Retrying in 30 seconds..."
sleep 30
done
fi
print_header()
lightcyan='\\033[1;36m'
nocolor='\\033[0m'
echo -e "$lightcyan$1$nocolor"
# Let the agent ignore the token env variables
export VSO_AGENT_IGNORE=AZP_TOKEN,AZP_TOKEN_FILE
print_header "1. Determining matching Azure Pipelines agent..."
print_header "url=$AZP_URL/_apis/distributedtask/packages/agent?platform=$TARGETARCH&top=1"
# AZP_AGENT_PACKAGES=$(curl -LsS \\
# -u user:$(cat "$AZP_TOKEN_FILE") \\
# -H 'Accept:application/json;' \\
# "$AZP_URL/_apis/distributedtask/packages/agent?platform=$TARGETARCH&top=1")
AZP_AGENT_PACKAGES=$(curl -LsS \\
--ntlm \\
-u build:$(cat "$AZP_TOKEN_FILE") \\
-H 'Accept:application/json;' \\
"$AZP_URL/_apis/distributedtask/packages/agent?platform=$TARGETARCH&top=1")
print_header "$AZP_AGENT_PACKAGES"
AZP_AGENT_PACKAGE_LATEST_URL=$(echo "$AZP_AGENT_PACKAGES" | jq -r '.value[0].downloadUrl')
# print_header "1.2 AZP_AGENT_PACKAGE_LATEST_URL=$AZP_AGENT_PACKAGE_LATEST_URL..."
if [ -z "$AZP_AGENT_PACKAGE_LATEST_URL" -o "$AZP_AGENT_PACKAGE_LATEST_URL" == "null" ]; then
echo 1>&2 "error: could not determine a matching Azure Pipelines agent"
echo 1>&2 "check that account '$AZP_URL' is correct and the token is valid for that account"
exit 1
fi
print_header "2. extracting Azure Pipelines agent..."
tar zxf ./vsts-agent-linux-x64-2.181.2.tar.gz & wait $!
#curl -LsS $AZP_AGENT_PACKAGE_LATEST_URL | tar -xz & wait $!
source ./env.sh
print_header "3. Configuring Azure Pipelines agent..."
./config.sh --unattended \\
--agent "$AZP_AGENT_NAME:-$(hostname)" \\
--url "$AZP_URL" \\
--auth negotiate \\
--userName build \\
--password $(cat "$AZP_TOKEN_FILE") \\
--pool "$AZP_POOL:-Default" \\
--work "$AZP_WORK:-_work" \\
--replace \\
--acceptTeeEula & wait $!
print_header "4. Running Azure Pipelines agent..."
trap 'cleanup; exit 0' EXIT
trap 'cleanup; exit 130' INT
trap 'cleanup; exit 143' TERM
chmod +x ./run.sh
# To be aware of TERM and INT signals call run.sh
# Running it with the --once flag at the end will shut down the agent after the build is executed
./run.sh "$@" & wait $!
当然大家也可以直接使用我已经做好了的镜像:ccr.ccs.tencentyun.com/xinlai/tfsagnet:latest
这样,代码都不用抄了,多省事。相关环境变量如下所示:
环境变量 | 说明 |
---|---|
AZP_URL | Azure DevOps 或Azure DevOps Server实例的 URL。 |
AZP_TOKEN | 密码。PAT认证有问题,被我改成了negotiate认证。 |
AZP_AGENT_NAME | 代理名称 (默认值:容器主机名) 。 |
AZP_POOL | 代理池名称 (默认值: Default ) 。 |
AZP_WORK | 工作目录 (默认值: _work ) 。 |
在Docker中运行
参考脚本:
docker run -e AZP_URL=<Azure DevOps instance> -e AZP_TOKEN=<密码> -e AZP_AGENT_NAME=mydockeragent ccr.ccs.tencentyun.com/xinlai/tfsagnet:latest
但是现在的构建离不开Docker,那么Docker in Docker我们肯定是需要的,修改后参考脚本如下所示:
docker run --name docker-ag \\
-e AZP_AGENT_NAME=docker-tx-ag \\
-e AZP_URL=\\
-e AZP_TOKEN=<密码> \\
-v /var/run/docker.sock:/var/run/docker.sock \\
-v /usr/bin/docker:/usr/bin/docker \\
--user root \\
--restart=always \\
ccr.ccs.tencentyun.com/xinlai/tfsagnet:latest
使用portainer来管理Docker代理
在一台服务器上跑了几个实例,为了便于管理,我们可以运行一个portainer实例来进行管理,参考脚本如下:
docker run -d -p 80:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --name prtainer portainer/portainer
然后我们就可以登录其Web管理界面来进行监控和管理:
portainer管理UI
我们可以在一台服务器多跑几个:
Docker代理
运行了之后,我们可以在Azure DevOps的默认代理池看到他们:
定时清理
基于容器构建很方便,但是费空间,尤其是高频次构建,多运行时构建时,各种悬浮镜像的存在,我们可以加个定时构建任务来进行清理,参考脚本如下:
docker system prune -a -f
这样,50G的系统盘一拖3个代理,也是够了。
最后
至此,整个教程到此就结束了。服务器推荐配置如下所示:
磁盘大小:30~50G,如代码文件过大可以适当增加空间以及增加自动清理的频率
内存:16~32G,如果只构建后端代码,8G也是够了,但是前端构建是个黑洞,很多代码构建时没个16G内存,会直接原地崩溃
CPU:4~8核
以上是关于基于Docker托管Azure DevOps代理的主要内容,如果未能解决你的问题,请参考以下文章
Azure DevOps 构建管道自托管代理“设备上没有剩余空间”
在 Service Fabric 中运行 Azure DevOps 自托管生成代理时出现“无法解析远程名称”
多目标 .NET Core 控制台的 Azure DevOps (VSTS) 托管 macOS 代理失败