如何部署一个bazel远程服务器?
常见的几种办法利用nginx部署远程缓存服务器1.制作一个nginx镜像(包含webdev)1.初始版本的dockerfile2.常见问题及解决办法 2. nginx服务器设置Q&A(常见问题与回答)将nginx服务器设置为缓存服务器需要进行的配置 3.本地bazel构建的项目关联远程缓存服务器(bind)Q:如何给本地项目绑定远程缓存服务器?Q:怎么测试构建时启用了远程缓存呢?Tip: 4.项目实践前提条件测试环节
常见的几种办法
利用nginx部署远程缓存服务器
1.制作一个nginx镜像(包含webdev)
原因:nginx官方提供的nginx镜像是没有webdev模块的,没有办法进行远程缓存服务器的设置。所以需要我们自己制作一个包含webdev模块的nginx镜像。
思路:写一个dockerfile,基于Ubuntu的基础镜像制新的nginx镜像。
1.初始版本的dockerfile
ARG BASE="ubuntu:20.04"FROM $BASECOPY sources.list ./ #source.list文件里面是Ubuntu的软件源信息RUN cp ./sources.list /etc/apt/sources.list && \ #将软件源信息拷贝到ubuntu镜像里 rm -rf ./sources.listRUN apt-get updateRUN apt-get install -y vimRUN apt-get install -y net-toolsRUN apt-get install -y nginx-extrasENV MYPATH /usr/localWORKDIR $MYPATHEXPOSE 80CMD echo "----- end -----"CMD /bin/bash
Ubuntu 的软件源配置文件是 /etc/apt/sources.list
2.常见问题及解决办法
1.无法正常的进行apt -get update操作
原因:
没有给Ubuntu镜像配置软件源,初始的Ubuntu镜像是什么都没有的Dockerfile里的基础镜像Ubuntu版本和软件源的版本不一致,如From Ubuntu
,默认基于最新的Ubuntu镜像,而软件源的设置是按其他版本的Ubuntu配置的,就可能无法正常update. 2.当我们执行docker build 生成镜像时debconf会问很多问题。
具体情况如下,会弹出很多question:
debconf: delaying package configuration, since apt-utils is not installedPlease select the geographic area in which you live. Subsequent configurationquestions will narrow this down by presenting a list of cities, representingthe time zones in which they are located. 1. Africa 4. Australia 7. Atlantic 10. Pacific 13. Etc 2. America 5. Arctic 8. Europe 11. SystemV 3. Antarctica 6. Asia 9. Indian 12. US
解决办法:
参考文章:Avoid apt-utils warning in Debian Dockerfile
我们可以通过在Dockerfile中执行RUN时加上 export DEBIAN_FRONTEND=noninteractive
如:RUN export DEBIAN_FRONTEND=noninteractive && ...
修改完的Dockerfile如下:
ARG BASE="ubuntu:20.04"FROM $BASECOPY sources.list ./RUN cp ./sources.list /etc/apt/sources.list && \ rm -rf ./sources.listRUN apt-get updateRUN DEBIAN_FRONTEND=noninteractive apt-get install -y vimRUN DEBIAN_FRONTEND=noninteractive apt-get install -y net-toolsRUN DEBIAN_FRONTEND=noninteractive apt-get install -y nginx-extrasENV MYPATH /usr/localWORKDIR $MYPATHEXPOSE 80CMD echo "----- end -----"CMD /bin/bash
但是此时的Dockerfile还是有问题,使用了太多的RUN指令,这样会产生很多的镜像层,使生成的镜像过于臃肿。所以我们可以将多个RUN指令进行合并,修改完的镜像如下:
ARG BASE="ubuntu:20.04"FROM $BASEENV TZ=Asia/Shanghai \ DEBIAN_FRONTEND=noninteractiveCOPY sources.list /etc/apt/sources.listRUN apt-get update && \ apt-get install -y nginx-extras && \ apt-get cleanCOPY nginx-bazel.conf /etc/nginx/sites-available/default #将本地写好的nginx配置文件直接复制到nginx镜像中RUN mkdir -p /huge/www/html /huge/www/cache /huge/client_temp \ #创建需要的缓存目录 /huge/log/nginx /app/src && \ chmod 777 /huge/www/cacheWORKDIR /app/src #设置工作目录EXPOSE 80CMD ["nginx", "-g", "daemon off;"] #容器启动时启动nginx服务
nginx-bazel.conf(服务器配置文件)
server { listen 80 default_server; root /huge/www; # Add index.php to the list if you are using PHP index index.html index.htm index.nginx-debian.html; server_name localhost; location /cache/ { root /huge/www; client_body_temp_path /huge/client_temp; dav_methods PUT DELETE MKCOL COPY MOVE; dav_ext_methods PROPFIND OPTIONS; dav_access user:rw group:rw all:rw; create_full_put_path on; client_max_body_size 2G; fancyindex on; access_log /huge/log/nginx/access.log; }}
相对于之前的镜像做出了以下改变
将多条指令合并,使镜像更轻量使用apt安装软件后,清理软件—>apt-get clean去掉了不需要的环境变量,以免污染容器环境工作目录最好新建一个目录,因为容器运行时可能生成其他文件,如果在系统目录下会有不可预知的风险产生将服务器的配置文件从本地直接拷贝到镜像的/etc/nginx/sites-available/目录下,直接重命名为default,覆盖了nginx服务器的初始设置。(避免手动设置服务器配置)直接在镜像构建时就将服务器的缓存目录给创建好,不需要手动创建了。添加CMD指令容器启动后就可以直接启动nginx服务了,相当于容器启动了,nginx缓存服务器就可以直接运行了。然后执行docker build,出现successfully就是成功了。
$ docker build -f Dockerfile -t bazel-cache-server:1.0 .Sending build context to Docker daemon 5.12kBStep 1/10 : ARG BASE="ubuntu:20.04"Step 2/10 : FROM $BASE ---> 20fffa419e3aStep 3/10 : ENV TZ=Asia/Shanghai DEBIAN_FRONTEND=noninteractive ---> Using cache ---> ec3f9852ed64Step 4/10 : COPY sources.list /etc/apt/sources.list ---> d11f607b4fc6Step 5/10 : RUN apt-get update && apt-get install -y nginx-extras && apt-get clean ---> Running in 25053684f808Step 6/10 : COPY nginx-bazel.conf /etc/nginx/sites-available/default ---> 2e2eb9e7efc5Step 7/10 : RUN mkdir -p /huge/www/html /huge/www/cache /huge/client_temp /huge/log/nginx /app/src && chmod 777 /huge/www/cache ---> Running in 85f986c8f2ddRemoving intermediate container 85f986c8f2dd ---> c5177bed8296Step 8/10 : WORKDIR /app/src ---> Running in 75f09e7e95b1Removing intermediate container 75f09e7e95b1 ---> 69cfad7b9688Step 9/10 : EXPOSE 80 ---> Running in 4828bd9e565aRemoving intermediate container 4828bd9e565a ---> 2ec31ba86e3cStep 10/10 : CMD ["nginx", "-g", "daemon off;"] ---> Running in 9c5fd100a93dRemoving intermediate container 9c5fd100a93d ---> 76847b7518d2Successfully built 76847b7518d2Successfully tagged bazel-cache-server:1.0$ lsDockerfile nginx-bazel.conf sources.list
最后查看是否生成了镜像:docker images
REPOSITORY TAG IMAGE ID CREATED SIZEbazel-cache-server 1.0 76847b7518d2 3 minutes ago 226MB
2. nginx服务器设置
nginx镜像制作完毕之后,我们就可以根据镜像启动一个nginx容器实例,那么该容器就是提供远程缓存功能的nginx服务器。
需要注意的是:启动容器后并没有直接启动容器中的nginx服务,容器相当于一个微型的操作系统,所以得进入容器里手动启动一下nginx服务,或者在制作镜像dockerfile中写好启动nginx的指令。
Q&A(常见问题与回答)
Q:如何启动容器?
A:由于Dockerfile中指明容器暴露的端口是80端口,说明启动的nginx容器(微型操作系统)的可访问端口是80端口,那么我们要把它映射成虚拟机的某个可用端口,这样才能够访问到该服务。具体示例如下:docker run --name mynginx -p 8089:80 -itd newnginx
说明:根据镜像newnginx启动一个新的容器实例,容器名字为mynginx,容器的80端口映射到虚拟机的8089端口。
Q:怎么进入容器内部?
A:docker exec -it mynginx bash
,mynginx是容器的名称
Q:如何在容器中启动nginx服务?
A:进入容器之后,首先用 ps aux | grep nginx
查看nginx服务是否启动。结果如下:
说明还没有启动nginx
root@09497a291a10:/usr/local# ps aux | grep nginxroot 22 0.0 0.0 3304 720 pts/1 S+ 10:27 0:00 grep --color=auto nginx
所以现在找一下nginx的启动程序,输入find / -name nginx
,结果如下:
root@09497a291a10:/usr/local# find / -name nginx/var/log/nginx/var/lib/nginx/etc/init.d/nginx/etc/logrotate.d/nginx/etc/default/nginx/etc/nginx/etc/ufw/applications.d/nginx/usr/share/nginx/usr/sbin/nginx/usr/lib/x86_64-linux-gnu/perl5/5.30/auto/nginx/usr/lib/nginx
可以判断出/etc/init.d目录就是初始化nginx服务的位置,首先切换到该路径下,然后执行nginx程序。具体指令为cd /etc/init.d && nginx
,执行结果如下。
root@09497a291a10:/etc/init.d# nginxroot@09497a291a10:/etc/init.d# ps aux | grep nginxroot 26 0.0 0.0 97340 5172 ? Ss 10:29 0:00 nginx: master process nginxwww-data 27 0.0 0.0 97692 6812 ? S 10:29 0:00 nginx: worker processwww-data 28 0.0 0.0 97692 6812 ? S 10:29 0:00 nginx: worker processwww-data 29 0.0 0.0 97692 6812 ? S 10:29 0:00 nginx: worker processwww-data 30 0.0 0.0 97692 6812 ? S 10:29 0:00 nginx: worker processwww-data 31 0.0 0.0 97692 6812 ? S 10:29 0:00 nginx: worker processwww-data 32 0.0 0.0 97692 6812 ? S 10:29 0:00 nginx: worker processwww-data 33 0.0 0.0 97692 6812 ? S 10:29 0:00 nginx: worker processwww-data 34 0.0 0.0 97692 6812 ? S 10:29 0:00 nginx: worker processroot 36 0.0 0.0 3304 656 pts/1 S+ 10:29 0:00 grep --color=auto nginx
Q:怎么测试nginx服务已经启动了?
A:两种方法:
一:在后台执行curl localhost:8089
,如果有返回数据就是服务已经成功启动了。
二:在浏览器中输入网址:虚拟机IP地址:8089(端口号)
,如:http://10.128.128.152:8089/,浏览器如果成功返回welcome nginx的页面就是证明nginx服务正常。
Welcome to nginx!If you see this page, the nginx web server is successfully installed and working. Further configuration is required.For online documentation and support please refer to nginx.org.Commercial support is available at nginx.com.Thank you for using nginx.
Q:怎么查看容器中nginx的日志?
A:用命令:tail -f /var/log/nginx/*.log
,效果如下:
==> /var/log/nginx/error.log <====> /var/log/nginx/access.log <==10.128.54.4 - - [16/Jun/2022:10:48:40 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36"10.128.54.4 - - [16/Jun/2022:10:48:42 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36"
将nginx服务器设置为缓存服务器需要进行的配置
准备操作:启动容器,进入容器内部,具体操作见上文。
docker run --name mynginx -p 8089:80 -itd newnginx 启动容器docker ps 查看启动的服务docker exec -it mynginx bash 进入容器进入容器后cd /etc/nginx此时你可以看到如下的目录:
root@09497a291a10:/var/log/nginx# cd /etc/nginxroot@09497a291a10:/etc/nginx# lsconf.d fastcgi_params koi-win modules-available nginx.conf scgi_params sites-enabled uwsgi_paramsfastcgi.conf koi-utf mime.types modules-enabled proxy_params sites-available snippets win-utf
我们关注sites-available
文件夹,该文件夹下有一个default文件,我们只要配置这个文件就可以。
root@09497a291a10:/etc/nginx# cd sites-available/root@09497a291a10:/etc/nginx/sites-available# lsdefault
编辑default文件,vi default
default文件:
server { listen 80 default_server; #监听端口,即容器内nginx服务启动的端口 listen [::]:80 default_server; root /huge/www; # Add index.php to the list if you are using PHP index index.html index.htm index.nginx-debian.html; server_name localhost; location /cache/ { root /huge/www; client_body_temp_path /huge/client_temp; dav_methods PUT DELETE MKCOL COPY MOVE; dav_ext_methods PROPFIND OPTIONS; dav_access user:rw group:rw all:rw; create_full_put_path on; client_max_body_size 2G; fancyindex on; access_log /huge/log/nginx/access.log; }}
然后我们将配置文件中的文件目录,在容器中进行创建。
mkdir -p /huge/www/htmlmkdir -p /huge/www/cache #缓存的文件主要就是存储在这里mkdir -p /huge/client_tempmkdir -p /huge/log/nginx
同时给文件夹/huge/www/cache
设置写入权限,否则当本地构建的结果上传到nginx缓存服务器时,会出现Permission denied
权限不够的错误,无法写入。
chmod 777 /huge/www/cache
root@09497a291a10:/huge/www# ls -lltotal 8drwxr-xr-x 2 root root 4096 Jun 16 11:20 cachedrwxr-xr-x 2 root root 4096 Jun 16 11:20 htmlroot@09497a291a10:/huge/www# chmod 777 cacheroot@09497a291a10:/huge/www# ls -lltotal 8drwxrwxrwx 2 root root 4096 Jun 16 11:20 cachedrwxr-xr-x 2 root root 4096 Jun 16 11:20 htmlroot@09497a291a10:/huge/www#
好了到这里服务器的配置已经成功设置好了,停止容器重启容器后,就可以了。现在只需要把本地用bazel构建的项目和远程的nginx缓存服务器进行关联即可。
exit退出容器docker stop mynginx 停止容器docker start mynginx 启动容器3.本地bazel构建的项目关联远程缓存服务器(bind)
前提条件:假设你已经具有成功用bazel构建项目的所有条件
本地有一个bazel项目安装了bazel依赖sudo apt install g++ unzip zip python3
安装了bazel Q:如何给本地项目绑定远程缓存服务器?
A:bazel的工作空间中有一个.bazelrc文件
,我们关注该文件,编辑该文件,添加以下信息.bazelrc
文件:
build --remote_cache=http://localhost:8089/cache#上面的地址就是缓存服务器的地址,根据你的服务器设置进行修改。
Q:怎么测试构建时启用了远程缓存呢?
A:主要测试有远程缓存和没有远程缓存的情况,具体操作如下:
在.bazelrc文件中设置远程缓存服务器地址,然后构建项目,可以看到构建结果上传到缓存服务器。$ make bazel-build ##用mak对项目进行了简单的管理INFO: Invocation ID: 3de47f29-51e3-43a6-ac4c-5b0acb998831 ===> Building tiger-controller with Bazel <===bazel build //cmd/tiger-controller:tiger-controllerINFO: Invocation ID: b5c13628-c91e-4ea4-8927-6fab62bf40dfINFO: Analyzed target //cmd/tiger-controller:tiger-controller (447 packages loaded, 11733 targets configured).INFO: Found 1 target...Target //cmd/tiger-controller:tiger-controller up-to-date: bazel-bin/cmd/tiger-controller/tiger-controller_/tiger-controllerINFO: Elapsed time: 4.463s, Critical Path: 1.71sINFO: 400 processes: 396 remote cache hit, 4 internal.===>表示有396个缓存命中INFO: Build completed successfully, 400 total actions
nginx缓存服务器中:
root@5a92a4a5e992:/huge/www/cache# ls -lhtotal 240Kdrwxrwxrwx 2 www-data www-data 52K Jun 16 14:32 acdrwxrwxrwx 2 www-data www-data 180K Jun 16 14:32 cas
接着清理构建结果,clean清理之后,在.bazelrc文件中注释掉指定远程缓存服务器的信息,再次构建项目。 INFO: Analyzed target //cmd/tiger-controller:tiger-controller (447 packages loaded, 11733 targets configured).INFO: Found 1 target...Target //cmd/tiger-controller:tiger-controller up-to-date: bazel-bin/cmd/tiger-controller/tiger-controller_/tiger-controllerINFO: Elapsed time: 29.083s, Critical Path: 21.15s===>构建时间明显变长了INFO: 400 processes: 4 internal, 396 linux-sandbox.INFO: Build completed successfully, 400 total actions
Tip:
远程缓存的作用:bazel第一次构建项目的时候,会将构建结果(二进制文件)上传到远程缓存服务器(nginx)上,构建结束后,你清理一下本地缓存,执行bazel clean
操作,然后再构建项目,执行bazel build
,就可以明显看到bazel直接从缓存服务器上拉取之前的构建结果,大大提升了构建速度。(构建的结果是以哈希值进行区分的)
本地构建到一半终止后,再次启用远程缓存构建时,会直接从缓存服务器中获得剩下的构建结果。
4.项目实践
现在nginx缓存服务器也搭好了,我们通过一个构建一个简单的cpp项目进行测试。
前提条件
从 Bazel 的 GitHub 代码库检索示例项目,clone到本地:git clone https://github.com/bazelbuild/examples
以容器方式启动的nginx缓存服务器地址:localhost:8089
构建的示例项目和nginx服务都在一台虚拟机上(可以在不同机器,只要可以互相访问即可) 测试环节
在样例程序中找到examples/cpp-tutorial/stage2
,然后新建一个.bazelrc文件,在文件中指明缓存服务器的地址:vi .bazelrc
.bazelrc文件
build --remote_cache=http://localhost:8089/cache
然后构建hello-world项目
➜ stage2 bazel build //main:hello-world #将构建结果上传到缓存服务器中INFO: Invocation ID: cb5b365a-24b7-45cf-b677-d84d8ed0da45INFO: Analyzed target //main:hello-world (37 packages loaded, 164 targets configured).INFO: Found 1 target...Target //main:hello-world up-to-date: bazel-bin/main/hello-worldINFO: Elapsed time: 1.087s, Critical Path: 0.53s #无缓存的构建速度INFO: 7 processes: 4 internal, 3 linux-sandbox.INFO: Build completed successfully, 7 total actions➜ stage2 bazel clean #清理本地缓存INFO: Invocation ID: 59a88152-76de-4cee-873a-11da4ca03200INFO: Starting clean (this may take a while). Consider using --async if the clean takes more than several minutes.➜ stage2 bazel build //main:hello-world #再次构建,会从服务器拉取已有的构建结果INFO: Invocation ID: 8252066f-f572-46e1-933c-94952c6ed439INFO: Analyzed target //main:hello-world (37 packages loaded, 164 targets configured).INFO: Found 1 target...Target //main:hello-world up-to-date: bazel-bin/main/hello-worldINFO: Elapsed time: 0.492s, Critical Path: 0.03s #有缓存的构建速度INFO: 7 processes: 3 remote cache hit, 4 internal.INFO: Build completed successfully, 7 total actions
查看缓存服务器多了什么:
root@5a92a4a5e992:/huge/www/cache/cas# ls0bfdc46886dacdb41269ae2ac22cd4f9ada203a37ea7fd9b260d2f2e96dd8fa6 9903ed97a739fda63c5731c3fa01a22a902763060ca7ed11cd2ab2462b08adee......root@5a92a4a5e992:/huge/www/cache/cas# cd ../acroot@5a92a4a5e992:/huge/www/cache/ac# ls96c5d143551dea69e8b2f418a22d66fb56d845933581dfe35f6d0180ca064ee9 e28750895c1576be99687f4379581f4f234c98f8a100dc616efeb8d20c6a3bcee02146d8850739017fe973e8fd2c769e7543bf48f9fd17b5ae0a7df5ede58b65
注:
Bazel 支持通过 HTTP/1.1 进行远程缓存。该协议在概念上很简单:二进制数据 (BLOB) 通过 PUT 请求上传,并通过 GET 请求下载。操作结果元数据存储在路径 /ac/ 下,输出文件存储在路径 /cas/ 下。