如何在Google Cloud Build的bash脚本启动的容器中挂载卷?
我有如下cloudbuild.yaml文件:
steps: - name: 'gcr.io/cloud-builders/gsutil' args: [ "-m", "rsync", "-r", "gs://${_BUCKET}/maven-repository", "/cache/.m2" ] volumes: - path: '/cache/.m2' name: 'm2_cache' - name: docker/compose:debian-1.29.2 entrypoint: bash args: - -c - | ./test.sh volumes: - path: '/cache/.m2' name: 'm2_cache' timeout: 2700s substitutions: _BUCKET: 'my-bucket'
第一步从GCS下载包含Artifact Registry Maven仓库凭据的settings.xml文件,这对后续构建至关重要。第二步执行test.sh脚本,脚本内容如下:
#!/bin/bash echo "### [Host] Contents in /cache/.m2" ls -la /cache/.m2 mkdir ~/test echo "Johan" > ~/test/ikk.txt echo "### [Host] Contents in ~/test" ls -la ~/test docker run --rm -v /cache/.m2:/cache/.m2 -v ~/test:/root/test -w /usr/src/somewhere ubuntu bash -c 'echo "### [Docker] Contents in /cache/.m2" && ls -la /cache/.m2 && echo "### [Docker] Contents in /root/test" && ls -la /root/test'
在Google Cloud Build中运行时,脚本启动的ubuntu容器内挂载的目录为空;但本地运行时容器能正常挂载并访问文件。请问如何在Google Cloud Build中实现容器内的卷挂载?
核心问题
Google Cloud Build的每个构建步骤本身运行在一个Docker容器(外层容器)中,而你在步骤内执行docker run时,调用的是Cloud Build宿主机的Docker守护进程。此时用-v /cache/.m2:/cache/.m2挂载的是宿主机的路径,而非外层容器的路径——外层容器的/cache/.m2和~/test并不存在于宿主机上,所以新启动的ubuntu容器挂载到的是空目录。
可行解决办法
1. 使用Cloud Build工作区目录(最简单)
Cloud Build默认会把代码仓库的工作区挂载到所有步骤容器的/workspace目录,这个目录在宿主机和步骤容器之间是共享的。修改路径到/workspace下即可:
修改cloudbuild.yaml第一步:
steps: - name: 'gcr.io/cloud-builders/gsutil' args: [ "-m", "rsync", "-r", "gs://${_BUCKET}/maven-repository", "/workspace/maven-cache" ] - name: docker/compose:debian-1.29.2 entrypoint: bash args: - -c - | ./test.sh timeout: 2700s
修改test.sh:
#!/bin/bash echo "### [Host] Contents in /workspace/maven-cache" ls -la /workspace/maven-cache mkdir /workspace/test echo "Johan" > /workspace/test/ikk.txt echo "### [Host] Contents in /workspace/test" ls -la /workspace/test docker run --rm -v /workspace/maven-cache:/cache/.m2 -v /workspace/test:/root/test -w /usr/src/somewhere ubuntu bash -c 'echo "### [Docker] Contents in /cache/.m2" && ls -la /cache/.m2 && echo "### [Docker] Contents in /root/test" && ls -la /root/test'
2. 使用Cloud Build全局缓存卷(推荐用于跨步骤缓存)
如果需要在多个构建步骤之间复用缓存,可以配置全局缓存卷,它会直接挂载到宿主机,这样docker run时能直接访问:
修改cloudbuild.yaml:
steps: - name: 'gcr.io/cloud-builders/gsutil' args: [ "-m", "rsync", "-r", "gs://${_BUCKET}/maven-repository", "/cache/.m2" ] - name: docker/compose:debian-1.29.2 entrypoint: bash args: - -c - | ./test.sh timeout: 2700s substitutions: _BUCKET: 'my-bucket' options: volumes: - name: 'm2_cache' path: '/cache/.m2'
修改test.sh(把测试目录也放到全局缓存路径下):
#!/bin/bash echo "### [Host] Contents in /cache/.m2" ls -la /cache/.m2 mkdir /cache/test echo "Johan" > /cache/test/ikk.txt echo "### [Host] Contents in /cache/test" ls -la /cache/test docker run --rm -v /cache/.m2:/cache/.m2 -v /cache/test:/root/test -w /usr/src/somewhere ubuntu bash -c 'echo "### [Docker] Contents in /cache/.m2" && ls -la /cache/.m2 && echo "### [Docker] Contents in /root/test" && ls -la /root/test'
3. 挂载步骤容器的文件系统(不推荐)
如果必须使用步骤内的命名卷,可以通过挂载步骤容器的文件系统到新容器,但需要获取步骤容器的ID,这种方法依赖Cloud Build底层实现,稳定性差:
# 在test.sh中添加 CONTAINER_ID=$(hostname) docker run --rm -v /var/lib/docker/containers/$CONTAINER_ID/mounts/merged/cache/.m2:/cache/.m2 -v /var/lib/docker/containers/$CONTAINER_ID/mounts/merged/root/test:/root/test ...
不建议生产环境使用这种方法,因为Cloud Build的容器存储路径可能会变化。
内容的提问来源于stack exchange,提问作者Johan

