diff --git a/.gitea/workflows/test-build.yaml b/.gitea/workflows/test-build.yaml index 80990b9..8a31e09 100644 --- a/.gitea/workflows/test-build.yaml +++ b/.gitea/workflows/test-build.yaml @@ -17,12 +17,12 @@ env: IMAGE: git.ivanch.me/ivanch/pipeline-actions-selftest jobs: - test-build-push: - name: Build tiny multi-arch image (${{ matrix.runner }}) + test-build-push-amd64: + name: AMD64 - Build tiny multi-arch image (${{ matrix.runner }}) runs-on: ${{ matrix.runner }} strategy: matrix: - runner: [runner-full-amd64, runner-full-arm64] + runner: [runner-slim-amd64, runner-full-amd64] steps: - name: Check out repository uses: actions/checkout@v4 @@ -60,12 +60,55 @@ jobs: echo "${MANIFEST}" | grep -q "linux/arm64" || { echo "missing linux/arm64"; exit 1; } echo "self-test PASSED: multi-arch image built and pushed" - test-k8s: - name: Test Kubernetes actions (${{ matrix.runner }}) + test-build-push-arm64: + name: ARM64 - Build tiny multi-arch image (${{ matrix.runner }}) runs-on: ${{ matrix.runner }} strategy: matrix: - runner: [runner-full-amd64, runner-full-arm64] + runner: [runner-slim-arm64, runner-full-arm64] + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Generate a minimal Dockerfile + shell: bash + run: | + mkdir -p _selftest + cat > _selftest/Dockerfile <<'EOF' + FROM alpine:3.20 + RUN echo "pipeline-actions self-test build OK" + CMD ["true"] + EOF + + - name: Build and push via composite action + uses: https://git.ivanch.me/ivanch/pipeline-actions/build-and-push@main + with: + image: ${{ env.IMAGE }} + image_tag: citest + build_context: _selftest + build_dockerfile: Dockerfile + registry_password: ${{ secrets.REGISTRY_PASSWORD }} + ssh_key: ${{ secrets.SSH_KEY_DOCKERBUILD }} + + - name: Verify pushed image is pullable and multi-arch + shell: bash + env: + IMAGE: ${{ env.IMAGE }} + run: | + echo "== inspecting ${IMAGE}:citest manifest ==" + docker buildx imagetools inspect "${IMAGE}:citest" + # Assert both target arches are present in the manifest list. + MANIFEST="$(docker buildx imagetools inspect "${IMAGE}:citest")" + echo "${MANIFEST}" | grep -q "linux/amd64" || { echo "missing linux/amd64"; exit 1; } + echo "${MANIFEST}" | grep -q "linux/arm64" || { echo "missing linux/arm64"; exit 1; } + echo "self-test PASSED: multi-arch image built and pushed" + + test-k8s-amd64: + name: AMD64 - Test Kubernetes actions (${{ matrix.runner }}) + runs-on: ${{ matrix.runner }} + strategy: + matrix: + runner: [runner-slim-amd64, runner-full-amd64] steps: - name: Check out repository uses: actions/checkout@v4 @@ -102,12 +145,149 @@ jobs: kubectl --kubeconfig=kubeconfig.yaml delete namespace pipeline-actions-test --ignore-not-found=true --wait=false fi - test-ssh: - name: Test SSH deploy action (${{ matrix.runner }}) + test-k8s-arm64: + name: ARM64 - Test Kubernetes actions (${{ matrix.runner }}) runs-on: ${{ matrix.runner }} strategy: matrix: - runner: [runner-full-amd64, runner-full-arm64] + runner: [runner-slim-arm64, runner-full-arm64] + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Apply test manifests + uses: https://git.ivanch.me/ivanch/pipeline-actions/kubectl-apply@main + with: + kube_config: ${{ secrets.KUBE_CONFIG }} + manifests: tests/manifests/test-namespace.yaml,tests/manifests/test-deployment.yaml + + - name: Restart test deployment + uses: https://git.ivanch.me/ivanch/pipeline-actions/deploy-restart@main + with: + kube_config: ${{ secrets.KUBE_CONFIG }} + deployment_name: pipeline-actions-test + namespace: pipeline-actions-test + + - name: Verify deployment rollout status + shell: bash + run: | + printf '%s' "${{ secrets.KUBE_CONFIG }}" | tr -d '\r' > kubeconfig.yaml + kubectl --kubeconfig=kubeconfig.yaml rollout status deployment/pipeline-actions-test -n pipeline-actions-test --timeout=60s + + - name: Clean up Kubernetes resources + if: always() + shell: bash + run: | + if [ -f kubeconfig.yaml ]; then + kubectl --kubeconfig=kubeconfig.yaml delete deployment pipeline-actions-test -n pipeline-actions-test --grace-period=0 --force --ignore-not-found=true + kubectl --kubeconfig=kubeconfig.yaml delete namespace pipeline-actions-test --ignore-not-found=true --wait=false + else + printf '%s' "${{ secrets.KUBE_CONFIG }}" | tr -d '\r' > kubeconfig.yaml + kubectl --kubeconfig=kubeconfig.yaml delete deployment pipeline-actions-test -n pipeline-actions-test --grace-period=0 --force --ignore-not-found=true + kubectl --kubeconfig=kubeconfig.yaml delete namespace pipeline-actions-test --ignore-not-found=true --wait=false + fi + + test-ssh-amd64: + name: AMD64 - Test SSH deploy action (${{ matrix.runner }}) + runs-on: ${{ matrix.runner }} + strategy: + matrix: + runner: [runner-slim-amd64, runner-full-amd64] + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Install and configure SSH server + shell: bash + run: | + sudo apt-get update + sudo apt-get install -y openssh-server + + # Ensure privilege separation directory exists + sudo mkdir -p /run/sshd + + # Generate host keys if missing + sudo ssh-keygen -A + + # Start sshd on a custom port 2222 to avoid port conflicts on the runner host + sudo /usr/sbin/sshd -p 2222 -o "ListenAddress 127.0.0.1" -o "UsePAM yes" + + # Configure passwordless SSH login for current user + mkdir -p ~/.ssh + ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_test + cat ~/.ssh/id_test.pub >> ~/.ssh/authorized_keys + chmod 700 ~/.ssh + chmod 600 ~/.ssh/authorized_keys + + # Establish environment variables for subsequent steps + echo "SSH_USER=$(whoami)" >> "$GITHUB_ENV" + echo "TEST_REMOTE_DIR=$HOME/ssh_deploy_test" >> "$GITHUB_ENV" + + # Write the private key to GitHub/Gitea env securely using multiline syntax + echo "SSH_PRIVATE_KEY<> "$GITHUB_ENV" + cat ~/.ssh/id_test >> "$GITHUB_ENV" + echo "EOF" >> "$GITHUB_ENV" + + - name: Verify SSH localhost access + shell: bash + run: | + ssh -p 2222 -i ~/.ssh/id_test -o StrictHostKeyChecking=accept-new "${SSH_USER}@127.0.0.1" "echo 'Localhost SSH OK'" + + - name: Set up remote compose directory and files + shell: bash + run: | + mkdir -p "${TEST_REMOTE_DIR}" + # We write a compose file containing nginx:latest + cat > "${TEST_REMOTE_DIR}/docker-compose.yml" <<'EOF' + services: + test-nginx: + image: nginx:latest + container_name: pipeline-actions-ssh-test + restart: always + EOF + + - name: Deploy via composite action with image override + uses: https://git.ivanch.me/ivanch/pipeline-actions/ssh-deploy@main + with: + ssh_host: "127.0.0.1" + ssh_port: "2222" + ssh_username: ${{ env.SSH_USER }} + ssh_key: ${{ env.SSH_PRIVATE_KEY }} + remote_dir: ${{ env.TEST_REMOTE_DIR }} + image: "nginx" + image_tag: "alpine" + + - name: Verify container started and image pin succeeded + shell: bash + run: | + echo "Checking container status..." + docker ps -a + STATUS=$(docker ps --filter "name=pipeline-actions-ssh-test" --format "{{.Status}}") + echo "Container status: ${STATUS}" + echo "${STATUS}" | grep -q "Up" || { echo "Container is not running"; exit 1; } + + echo "Checking image pin..." + IMAGE_USED=$(docker inspect pipeline-actions-ssh-test --format '{{.Config.Image}}') + echo "Container is using image: ${IMAGE_USED}" + echo "${IMAGE_USED}" | grep -q "nginx:alpine" || { echo "Image pin failed"; exit 1; } + echo "self-test PASSED: container is running and using nginx:alpine" + + - name: Clean up SSH deployment resources + if: always() + shell: bash + run: | + if [ -d "${TEST_REMOTE_DIR}" ]; then + cd "${TEST_REMOTE_DIR}" + docker compose down || true + rm -rf "${TEST_REMOTE_DIR}" + fi + + test-ssh-arm64: + name: ARM64 - Test SSH deploy action (${{ matrix.runner }}) + runs-on: ${{ matrix.runner }} + strategy: + matrix: + runner: [runner-slim-arm64, runner-full-arm64] steps: - name: Check out repository uses: actions/checkout@v4 diff --git a/images/slim/Dockerfile b/images/slim/Dockerfile index 6b7925d..7c07de6 100644 --- a/images/slim/Dockerfile +++ b/images/slim/Dockerfile @@ -12,7 +12,8 @@ RUN apk add --no-cache \ ca-certificates \ tar \ gzip \ - nodejs + nodejs \ + docker-cli # Download and install kubectl matching the target architecture RUN KUBE_VER=$(curl -L -s https://dl.k8s.io/release/stable.txt) && \