作者 青鸟
最近的实习工作中,遇到了一个有意思的需求,特此记录一下,github action自动构建镜像的方案
问题
传统的github action构建镜像的场景针对的场景是固定的Dockerfile和镜像名称。但是我们的需求是针对每一个push或者pr的Dockerfile自动构建出相应的镜像。于是乎我们需要从commit中提取出Dockerfile的路径与构建镜像的名称,并自动构建与推送镜像。
解决
我们可以编写一个shell脚本,使用git diff提取出变化或者添加了的Dockerfile文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| #!/bin/bash
# 获取变更的文件列表 DIFF_OUTPUT=$(git diff --name-only "$1" "$2"|grep Dockerfile)
# 提取上一级目录 PARENT_DIRS=() FILE_PATHS=() for FILE_PATH in $DIFF_OUTPUT; do if [[ ! -f "$FILE_PATH" ]]; then echo "File $FILE_PATH does not exist, skipping." continue fi PARENT_DIR=$(dirname "$FILE_PATH" | awk -F'/' '{print $(NF)}') PARENT_DIRS+=("$PARENT_DIR") FILE_PATHS+=("$FILE_PATH") done
# 将数组转换为字符串 PARENT_DIRS_STRING=$(IFS=,; echo "${PARENT_DIRS[*]}") DIFF_OUTPUT_STRING=$(IFS=,; echo "${FILE_PATHS[*]}") echo "PARENT_DIRS=$PARENT_DIRS_STRING" echo "DIFF_OUTPUT=$DIFF_OUTPUT_STRING"
# 输出到环境变量 echo "PARENT_DIRS=$PARENT_DIRS_STRING" >> $GITHUB_ENV echo "DIFF_OUTPUT=$DIFF_OUTPUT_STRING" >> $GITHUB_ENV
|
上述脚本在获取了文件之后将变化了的Dockerfile的文件路径与上一级目录的名字存入了环境变量中,之后就是构建镜像了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| #!/bin/bash
# 打印环境变量以进行调试 echo "PARENT_DIRS=$PARENT_DIRS" echo "DIFF_OUTPUT=$DIFF_OUTPUT"
# 将环境变量读取为数组 IFS=',' read -r -a DIFF_OUTPUT_ARRAY <<< "$DIFF_OUTPUT" IFS=',' read -r -a PARENT_DIRS_ARRAY <<< "$PARENT_DIRS"
# 打印数组内容以进行调试 echo "DIFF_OUTPUT array: ${DIFF_OUTPUT_ARRAY[@]}" echo "PARENT_DIRS array: ${PARENT_DIRS_ARRAY[@]}"
# 构建并推送每个Docker镜像 for i in "${!DIFF_OUTPUT_ARRAY[@]}"; do DOCKERFILE_PATH=${DIFF_OUTPUT_ARRAY[$i]} PARENT_DIR=${PARENT_DIRS_ARRAY[$i]} TAG="$PARENT_DIR:latest" echo "Building and pushing image for $DOCKERFILE_PATH with tag $TAG and user as $DOCKER_USERNAME" docker buildx build --push \ --file $DOCKERFILE_PATH \ --platform linux/amd64\ --tag "$DOCKER_USERNAME/$TAG" \ . done
|
这样子变可以通过环境变量中的文件路径与上一级目录名来构建镜像
完整的github-action文件如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| name: Build Docker Images
on: push: branches: ['main']
jobs: build: runs-on: ubuntu-latest strategy: matrix: directory: [system] name: [devbox-system]
steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Get changed files id: getfile run: | chmod +x script/get_changed_files.sh script/get_changed_files.sh ${{ github.event.before }} ${{ github.sha }} shell: bash
- name: Echo output run: | echo "Changed files: ${{ env.DIFF_OUTPUT }}" echo "Parent directories: ${{ env.PARENT_DIRS }}"
- name: Set up Docker Buildx uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push Docker image run: | chmod +x script/build_and_push_images.sh script/build_and_push_images.sh env: DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} shell: bash
|
这样子我们就可以在每一次push的时候自动构建镜像并推送到docker hub中了。