在现代软件开发中,保持 Docker 镜像的最新状态对于确保应用的安全性和稳定性至关重要。本文将详细介绍如何使用 GitHub Actions 自动检查服务器上的 Docker 镜像,并与 Docker Hub 上的最新版本进行比较,以确保镜像保持最新。

前提条件

在开始之前,您需要具备以下条件:

  • GitHub 仓库:您需要一个托管代码的 GitHub 仓库。
  • 服务器访问权限:确保您有权限访问托管 Docker 镜像的服务器,并能够通过 SSH 登录。
  • Docker 基础知识:了解 Docker 镜像和容器的基本概念。

步骤详解

1. 创建 GitHub Actions 工作流文件

在您的 GitHub 仓库中,创建一个新的工作流文件,例如 .github/workflows/check_docker_update.yml。该文件将定义工作流的触发条件和执行步骤。

name: 检查 Docker 镜像更新

on:
  schedule:
    - cron: '0 0 * * *'  # 每天午夜运行
  workflow_dispatch:    # 允许手动触发

jobs:
  check-docker:
    runs-on: ubuntu-latest

    steps:
      - name: 获取服务器上的 Docker 镜像
        run: |
          sshpass -p "${{ secrets.SSH_PASSWORD }}" ssh -v -o StrictHostKeyChecking=no -p 端口默认21 ssh用户@ssh的ip "docker images --format '{{.Repository}}:{{.Tag}} {{.CreatedAt}}'" > images.txt
        env:
          SSH_PASSWORD: ${{ secrets.SSH_PASSWORD }}
      
      - name: 检查镜像更新
        run: |
          while IFS= read -r IMAGE; do
            # 提取镜像名称与标签信息以及创建时间
            REPO_TAG=$(echo "$IMAGE" | awk '{print $1}')
            CREATED_AT=$(echo "$IMAGE" | awk '{print $2" "$3" "$4}')
            
            REPO=$(echo "$REPO_TAG" | cut -d ':' -f1)
            TAG=$(echo "$REPO_TAG" | cut -d ':' -f2)
            
            # 检查本地镜像创建时间格式是否有效
            if ! date -d "$CREATED_AT" &>/dev/null; then
              echo "$REPO_TAG 的创建时间无效,跳过检查"
              continue
            fi

            # 从 Docker Hub 获取最新标签和更新时间(注意:此API仅适用于官方镜像)
            RESPONSE=$(curl -s "https://hub.docker.com/v2/repositories/library/$REPO/tags")
            LATEST_TAG=$(echo "$RESPONSE" | jq -r '.results[0].name')
            LATEST_UPDATED=$(echo "$RESPONSE" | jq -r '.results[0].last_updated')
            
            if [ "$LATEST_TAG" = "null" ] || [ "$LATEST_UPDATED" = "null" ]; then
              echo "无法获取 $REPO 的最新标签信息"
              continue
            fi
            
            # 将日期转换为时间戳进行比较
            LOCAL_TIMESTAMP=$(date -d "$CREATED_AT" +%s)
            LATEST_TIMESTAMP=$(date -d "$LATEST_UPDATED" +%s)
            
            echo "------------------------------------------------"
            echo "检查镜像: $REPO_TAG"
            echo "本地镜像创建时间: $CREATED_AT (timestamp: $LOCAL_TIMESTAMP)"
            echo "Docker Hub 最新标签: $LATEST_TAG (更新时间: $LATEST_UPDATED, timestamp: $LATEST_TIMESTAMP)"
            
            if [ "$TAG" != "$LATEST_TAG" ]; then
              echo "$REPO_TAG 的本地标签 ($TAG) 与最新标签 ($LATEST_TAG) 不一致,建议更新。"
            else
              # 当标签一致,再进行日期对比
              if [ "$LOCAL_TIMESTAMP" -ne "$LATEST_TIMESTAMP" ]; then
                echo "$REPO_TAG 的标签一致,但更新时间不匹配,建议更新。"
              else
                echo "$REPO_TAG 已是最新,无需更新。"
              fi
            fi

          done < images.txt

工作流解释:

  1. 触发条件:

    • schedule:设置为每天午夜(00:00)运行一次检查。
    • workflow_dispatch:允许手动触发工作流。
  2. 作业定义(jobs):

    • check-docker:在最新的 Ubuntu 环境上运行。
    • 步骤(steps):
      • 获取服务器上的 Docker 镜像:
        • 使用 sshpass 通过 SSH 登录到服务器,执行 docker images 命令,获取所有镜像的信息,并将其保存到 images.txt 文件中。
      • 检查镜像更新:
        • 逐行读取 images.txt 文件,提取镜像名称、标签和创建时间。
        • 验证本地镜像的创建时间格式是否有效。
        • 使用 Docker Hub 的 API 获取官方镜像的最新标签和更新时间。
        • 将日期转换为时间戳进行比较。
        • 比较本地镜像与 Docker Hub 上最新标签的关系,并输出相应的建议。

注意:

  • 此工作流假设您使用的是官方的 Docker 镜像库(即镜像名称以 library/ 开头)。如果您使用的是其他镜像源,您可能需要调整 API 请求的 URL。
  • 确保您的服务器允许 SSH 登录,并且您提供的 SSH 密码或密钥正确无误。
  • 在 GitHub 仓库的 Settings 的 Secrets ( Settings-> Secrets and variables -> Actions)中添加 SSH_PASSWORD 等密钥,以确保密码的安全性。

总结

通过上述步骤,您可以使用 GitHub Actions 自动化地检查和更新服务器上的 Docker 镜像。这种自动化方法不仅提高了工作效率,还确保了应用环境的最新性和安全性。根据您的实际需求,您可以进一步优化和定制此工作流,例如添加通知功能或扩展对其他镜像源的支持。