在国内阿里云ECS上搞环境小贴士

昨天下午对一台阿里云的线上测试环境的机器进行压测,压到快下班的时候所有容器都挂了,机器上的HAProxy启动不了,我直接敲sudo reboot重启机器,结果机器再起不能。

抱着希望提了个工单,好长时间没人理,挺绝望的。我于是下定决心强行关机,重装系统,系统启动正常之后,邮件、短信通知我工单系统有回复了:

我坚信比我还专业的阿里云工程师肯定看不上我这样的运维,于是五星好评分期付款,开始跑机器初始化脚本。

初始化很快,建立用户、Docker还有各种Packages一下子就安装好了,最后安装HAProxy、Ansible和配置Jenkins的时候击碎了我的玻璃心,网络要么无法连接,要么是100B/s的下载速度,后面试了很多方法,加快了这个速度,遂记录下来以示后人。以下均为阿里云于2020年4月17日19点提供的Ubuntu 16.04的ECS主机上的操作。

HAProxy

自带的源更新到最新之后,HAProxy为1.6.X版本,不支持在监听上追加expose-fd listeners,也就是0宕机重载功能,这个特性在1.8版本上才支持光速吟唱:简单点就是本质上是利用新Linux Kernel里SO_REUSEPORT的Socket选项,允许同一台主机上的多个Socket同时binding在同一个TCP Port上,HAProxy在reload时把旧进程listener FD传给新进程listener,旧进程处理完当前连接后退出,新进程处理新的用户连接。整个过程新进程也binding到了原有的listener FD上,在整个过程中不会有连接被关闭。

那装1.8吧

sudo add-apt-repository ppa:vbernat/haproxy-1.8
sudo apt update
sudo apt install haproxy

这个过程要40分钟,阿里云ECS下载速度是107B/s左右

实际上更推荐装2.0,支持Prometheus直接获取metrics,不需要额外开stats frontend加装exporter收集metrics

就是阿里云SLB不支持TCP挂载SSL证书所以我才要大费周章搞HAProxy挂载SSL证书导致一台机器最多只能挂65535个连接才需要压测,一切的起源就是因为这个,所以全是阿里云的错

Python 2/3

系统默认带Python 2.7.4和Python 3.5.1,跑Ansible的时候疯狂提示我在使用的是过期的Python版本,在开发环境上可能我会搞搞pyenv,单一用途的测试环境怎么快怎么来:删除了Python 2,将Python 3链到/usr/bin/python上:

sudo apt remove python
sudo ln -s /usr/bin/python3 /usr/bin/python

同事当时提供了一个思路,就是把/usr/bin/ansible上的shebang改成/usr/bin/python3,当时未奏效,抛一堆的no module name xxx错误,没去想为什么。今天检查发现是Ansible依赖的module没有正确装上,最快的办法就是搞好Python之后一行命令pip install ansible就好

Jenkins

盲目分析

Sean前几天跟我说他把Jenkins放在Docker里面跑,我好像给他发了这篇文章:Alpine makes Python Docker builds way too(50×) slower, and images double(2×) larger

从各种实用角度和意义上,在Docker里面跑Jenkins挺麻烦的:

  • 齐全编译环境准备,Python、JDK、Gradle、npm、yarn、bazel,在国内搞一次欲仙欲死
  • 重复利用dependencies、modules需要很多额外工作
  • 简单点可以docker mount volume
  • 复杂点可以上repository mirrors
  • 启停Jenkins都需要花比较长的时间
  • Jenkins的DSL(JenkinsFile)、API很难用

我特别推荐简单环境下直接拿War包启动,泛用性极高,只要以当前用户身份把所有的环境设置好,java -jar jenkins.war启动,在Jenkins里就能拿用户身份的bash搞事,以下的操作也是在这种环境这么玩

SDKMAN

近几年各种JDK百花齐放齐头并进,什么Corretto、GraalVM、Liberica、SapMachine这些都没听说过,一直在用AdoptOpenJDK,出来个SDKMAN很方便地安装各种各样的JDK,附带JDK相关的工具比如Gradle、Maven、Spring Boot CLI啊也都有,没有Nodejs、Python这些比较可惜,在JVM栈上开发经常会用到,安装也简单:

curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"
sdk install java 8.0.242.hs-adpt
sdk install gradle
sdk install maven
sdk install springboot

配置完毕了开Jenkins这些就能用到了

Jenkins网络连接性和插件镜像调整

Jenkins会很机智智障地使用是否能连上Google作为网络连接性测试,国内自然是完全连不上一些地区除外

初次启动Jenkins时需要输入启动密码,接下来的页面就提示你是否需要设置代理,或者跳过下载推荐插件。这个时候很多人就会想,不就是下载推荐插件嘛,偏不下,直接点跳过下载插件。请不要这样做。这会导致很多插件需要手补,不了解依赖关系的你会补到想哭,那个插件页面又卡又烂,我补了好长时间,下载又花了好长时间,特别惨。

将Jenkins停止,调整如下配置:

调整网络连接性测试链接,用VIM打开~/.jenkins/updates/default.json,第一行第一个Key就是connectionCheckUrl,将www.google.com替换成Jenkins能连上的网站。

修改插件镜像,用VIM打开~/.jenkins/hudson.model.UpdateCenter.xml,把里面url替换为https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json

重新启动Jenkins,进行初始化,Jenkins下载插件的时候就有冲浪的感觉啦。

Git Clone超时时间

在阿里云ECS上git clone是地狱的感觉,10分钟内如果没有clone结束那么Jenkins就会主动停止,像这样:

此时需要在Item里面的Git -> Additional Behaviours -> Add -> Advanced clone behaviours -> Timeout (in minutes) for clone and fetch operations里填入Timeout时间,看看上面的网络速度,建议填个大一点的

Item备份

Jenkins之前推了个JenkinsFile,之前以为不用很麻烦很累就可以轻松配置Jenkins,后来发现因为Plugin不支持,还不如手点,Jenkins又不提供备份恢复选项,直到我发现了这么一个小插件:ThinBackup

使用前请在Settings里面设置存放路径。

当时在弗吉尼亚辛辛苦苦点到吐血的Jenkins配置,用这个插件直接备份,到法兰克福直接恢复,再改改点东西,直接就能用了。在Jenkins完全配置好之后,通过这个插件把配置备份一下,万劫不复时候掏出来直接恢复,能省至少1小时。

Gradle

Gradle编译的时候我在场,平时需要1分30秒,这次整个过程需要46分钟18秒,下载依赖需要了快3刻钟的时间。

项目里并没有使用特定的依赖仓库镜像,前端进行yarn install也只花了133秒,慢都是在后端。

可以使用Gradle的编译变量,在build script里面做个分支,编译的时候 gradle -Pxxx=xxx将变量传进去用不同的仓库镜像能快很多。

结语

要做到一件事,在这样的网络环境下多了这么多弯弯绕绕,还会为此写一篇文章记录这些调整,真是让人头顶青天泪流满面语不成声哑然失笑扼腕叹息

Show Comments