基于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 -yRUN 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-ntlmsspRUN curl -sL https://aka.ms/InstallAzureCLIDeb | bash# Can be 'linux-x64', 'linux-arm64', 'linux-arm', 'rhel.6-x64'.
ENV TARGETARCH=linux-x64WORKDIR /azp
COPY ./start.sh .
COPY ./vsts-agent-linux-x64-2.181.2.tar.gz .
RUN chmod +x start.shENTRYPOINT [ "./start.sh" ]

如果对Dockerfile不理解,可以参考笔者之前的教程、博客和书籍《Docker+Kubernetes应用开发与快速上云》来解决问题以及查看日志。这里不建议大家使用官方教程,基本上走不通还问题颇多。

值得注意的是,上面涉及到了两个文件:

  1. start.sh

  2. vsts-agent-linux-x64-2.181.2.tar.gz(从Azure DevOps管理界面下载)

start.sh脚本内容参考如下:

#!/bin/bash
set -eif [ -z "$AZP_URL" ]; thenecho 1>&2 "error: missing AZP_URL environment variable"exit 1
fiif [ -z "$AZP_TOKEN_FILE" ]; thenif [ -z "$AZP_TOKEN" ]; thenecho 1>&2 "error: missing AZP_TOKEN environment variable"exit 1fiAZP_TOKEN_FILE=/azp/.tokenecho -n $AZP_TOKEN > "$AZP_TOKEN_FILE"
fiunset AZP_TOKENif [ -n "$AZP_WORK" ]; thenmkdir -p "$AZP_WORK"
fiexport AGENT_ALLOW_RUNASROOT="1"cleanup() {if [ -e config.sh ]; thenprint_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") && breakecho "Retrying in 30 seconds..."sleep 30donefi
}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_FILEprint_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" ]; thenecho 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
fiprint_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.shprint_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' TERMchmod +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_URLAzure 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管理界面来进行监控和管理:

658a20c88bf8677f26534a86dfa2a28b.png

portainer管理UI

我们可以在一台服务器多跑几个:

76abcefcdb6a2cb067ea0a3df4056236.png

Docker代理

运行了之后,我们可以在Azure DevOps的默认代理池看到他们:

3def41181609cc4e2ed62e0000de66c4.png

定时清理

基于容器构建很方便,但是费空间,尤其是高频次构建,多运行时构建时,各种悬浮镜像的存在,我们可以加个定时构建任务来进行清理,参考脚本如下:

docker system prune -a -f

这样,50G的系统盘一拖3个代理,也是够了。

最后

至此,整个教程到此就结束了。服务器推荐配置如下所示:

  • 磁盘大小:30~50G,如代码文件过大可以适当增加空间以及增加自动清理的频率

  • 内存:16~32G,如果只构建后端代码,8G也是够了,但是前端构建是个黑洞,很多代码构建时没个16G内存,会直接原地崩溃

  • CPU:4~8核

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/280097.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微软 word转换pdf_如何将行转换为Microsoft Word表中的列

微软 word转换pdfYou’ve created a table in Word and started to enter your data. Then, you realize that the table should be transposed, meaning the rows should be columns and vice versa. Rather than recreating the table and manually entering the data again,…

pycharm中如何正确配置pyqt5

网上看了几个文章&#xff0c;不成功。这样做才是正确姿势&#xff1a; /Users/mac/anaconda3/bin/Designer.app /Users/mac/anaconda3/bin$ProjectFileDir$ pyuic5 $FileName$ -o $FileNameWithoutExtension$.py $ProjectFileDir$ 其它细节懒得说。 转载于:https://www.cnblog…

JS常用的设计模式

持续更新JS常用的设计模式以及应用场景*以下内容为个人简单理解以及摘抄部分网上demo组成&#xff0c;有错误请在下方评论指出?*# 何谓设计模式没必要被高大上的名词所吓倒&#xff0c;日常coding中或许一个不了解各种设计模式的程序员可能自己其实已经用到了很多抛开官方的定…

如何在Photoshop中制作双曝光图像

Double exposure images are popular at the moment. Taylor Swift’s Style music video and the True Detective opening theme both used the effect. It’s a technique where two separate photos—typically a portrait and a landscape—are blended together into one …

记一次.NET 某安全生产系统 CPU爆高分析

一&#xff1a;背景 1.讲故事今天是&#x1f40f;的第四天&#xff0c;头终于不巨疼了&#xff0c;写文章已经没什么问题&#xff0c;赶紧爬起来写。这个月初有位朋友找到我&#xff0c;说他的程序出现了CPU爆高&#xff0c;让我帮忙看下怎么回事&#xff0c;简单分析了下有两点…

JDBC 学习笔记(一)—— JDBC 基础

1. 什么是 JDBC JDBC&#xff0c;Java Database Connectivity&#xff08;Java 数据库连接&#xff09;&#xff0c;是一组执行 SQL 语句的 Java API。 JDBC&#xff0c;是 Java SE&#xff08;Java Platform, Standard Edition&#xff09;标准的一部分。 Java 程序可以通过 J…

JavaScript享元模式

JavaScript享元模式 通过两个例子的对比来凸显享元模式的特点&#xff1a;享元模式是一个为了提高性能(空间复杂度)的设计模式&#xff0c;享元模式可以避免大量非常相似类的开销。 第一实例&#xff0c;没有使用享元模式&#xff0c;计算所花费的时间和空间使用程度。 要求为&…

mac屏幕截图_如何在Mac上拍摄屏幕截图

mac屏幕截图On a Mac, you can take screenshots with a few quick keyboard shortcuts. But Mac OS X also includes more powerful screenshot tools, too. Here are some of the many ways you can get a screenshot on OS X. 在Mac上&#xff0c;您可以使用一些快速的键盘快…

实现 .Net 7 下的数据库定时检查

在软件开发过程中&#xff0c;有时候我们需要定时地检查数据库中的数据&#xff0c;并在发现新增数据时触发一个动作。为了实现这个需求&#xff0c;我们在 .Net 7 下进行一次简单的演示。PeriodicTimer .Net 6 中新增了 PeriodicTimer 这个类&#xff0c;它可以用来创建一个定…

新手AS常见问题集锦

开发环境 以前开发android的时候可以使用eclipse&#xff0c;虽然现在也能使用eclipse&#xff0c;但是google已经不再支持使用eclipse开发android了。因为google有了自己的IDE---android studio&#xff0c;这个IDE我自己认为安装的时候比较方便&#xff0c;唯一的缺点就是在下…

js进阶 11-6 jquery如何获取和设置元素的宽高(jquery多方法)

js进阶 11-6 jquery如何获取和设置元素的宽高&#xff08;jquery多方法&#xff09; 一、总结 一句话总结&#xff1a;jquery里面多是方法啊&#xff0c;比如jquery对象的宽高。所以取值是方法&#xff0c;赋值就是方法里面带参数。 1、百度富文本编辑器ueditor如何设置宽高&a…

SparseArray代替HashMap

相信大家都明白&#xff0c;手机软件的开发不同于PC软件的开发&#xff0c;因为手机性能相对有限&#xff0c;内存也有限&#xff0c;所谓“寸土寸金”&#xff0c;可能稍有不慎&#xff0c;就会导致性能的明显降低。Android为了方便开发者&#xff0c;特意在android.util这个包…

也许你曾经读过他的书

我们愿用“能理能文、才华多元”来形容他。因为热爱编程和游戏&#xff0c;所以他将爱好变成了职业&#xff0c;并在这条路上持续奔跑&#xff1b;因为热爱分享&#xff0c;所以他坚持在博客上分享技术观点并出版了关于 Azure、微软游戏栈的书籍&#xff1b;因为热爱挑战&#…

python测试框架数据生成工具最全资源汇总

xUnit frameworks 单元测试框架frameworks 框架unittest - python自带的单元测试库&#xff0c;开箱即用unittest2 - 加强版的单元测试框架&#xff0c;适用于Python 2.7以及后续版本pytest - 成熟且功能强大的单元测试框架plugincompat - pytest的执行及兼容性插件nosetests -…

t30智能插座怎么设置_如何设置ConnectSense智能插座

t30智能插座怎么设置If you like the idea of smart outlets, but wish you had one with more than just one receptacle on it, the ConnectSense Smart Outlet is worth looking into. Here’s how to set it up and instantly get double the fun. 如果您喜欢智能插座的想法…

用链表和数组实现HASH表,几种碰撞冲突解决方法

Hash算法中要解决一个碰撞冲突的办法&#xff0c;后文中描述了几种解决方法。下面代码中用的是链式地址法&#xff0c;就是用链表和数组实现HASH表。 he/*hash table max size*/ #define HASH_TABLE_MAX_SIZE 40/*hash table大小*/ int hash_table_size0;/*.BH----------------…

安卓操作sqlite3,增删改查

创建 layout <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"android:orientation"vertical"android:layout_width"match_parent"android:layo…

基于.NetCore开发博客项目 StarBlog - (23) 文章列表接口分页、过滤、搜索、排序

1前言上一篇留的坑&#xff0c;火速补上。在之前的第6篇中&#xff0c;已经有初步介绍&#xff0c;本文做一些补充&#xff0c;已经搞定这部分的同学可以快速跳过&#xff0c;基于.NetCore开发博客项目 StarBlog - (6) 页面开发之博客文章列表对标准的WebApi来说&#xff0c;分…

如何在Chrome中保存您当前的所有标签,以便以后阅读

Chrome allows you to open tabs from your last browsing session when you open the browser. However, what if you want to save your current set of tabs to re-open at any time? Chrome doesn’t provide a way to do that natively, but there is an easy workaround…

ubuntu 16.04(Windows 10双系统+grub引导)无法进入tt1~tt6(NVIDIA驱动安装相关-黑屏,login loop,分辨率)...

目录 前言回顾最终解决&#xff1a;0.关闭x服务1.禁用nouveau2.加入3.更新4.查找匹配驱动5.选择推荐版本6.等待安装后重启,nvidia-smi查看是否安装成功,或者lsmod | grep nvidia&#xff0c;成功结果如下7.重启x服务8.此时还不能进入图形界面&#xff0c;因为nomodeset还在&…