From 9cef77dece7963fe16cb390ff754a7936ba93d8d Mon Sep 17 00:00:00 2001 From: Valmira Nogueira Date: Fri, 13 Jun 2025 16:12:26 -0300 Subject: [PATCH 1/5] Add docker image to run tests on pipelines --- .github/workflows/build-cloud-qa.yaml | 67 +++++++++++++++++++++++++++ cloud/jenkins/docker/Dockerfile | 66 ++++++++++++++++++++++++++ cloud/jenkins/docker/pyproject.toml | 26 +++++++++++ 3 files changed, 159 insertions(+) create mode 100644 .github/workflows/build-cloud-qa.yaml create mode 100644 cloud/jenkins/docker/Dockerfile create mode 100644 cloud/jenkins/docker/pyproject.toml diff --git a/.github/workflows/build-cloud-qa.yaml b/.github/workflows/build-cloud-qa.yaml new file mode 100644 index 0000000000..567fb133f2 --- /dev/null +++ b/.github/workflows/build-cloud-qa.yaml @@ -0,0 +1,67 @@ +name: Weekly Docker Image Build - perconalab/cloud-qa + +on: + schedule: + - cron: '0 3 * * 1' # Every Monday at 03:00 UTC + +jobs: + build-and-push: + runs-on: ubuntu-latest + + env: + DOCKER_PROJECT: perconalab/cloud-qa + DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} + DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} + + steps: + - name: Fetch latest version tag from Docker Hub + id: get_version + run: | + echo "Fetching tags of $DOCKER_PROJECT from Docker Hub..." + + RESPONSE=$(curl -s -u "$DOCKERHUB_USERNAME:$DOCKERHUB_TOKEN" \ + "https://hub.docker.com/v2/repositories/$DOCKER_PROJECT/tags/?page_size=100") + + TAGS=$(echo "$RESPONSE" | jq -r '.results // [] | .[].name') + + if [ -z "$TAGS" ]; then + echo "No tags found. Starting from v1.0.0" + NEW_VERSION="v1.0.0" + else + LATEST_TAG=$(echo "$TAGS" | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -n1) + echo "Latest tag found: $LATEST_TAG" + + if [ -z "$LATEST_TAG" ]; then + NEW_VERSION="v1.0.0" + else + IFS='.' read -r MAJOR MINOR PATCH <<< "${LATEST_TAG#v}" + PATCH=$((PATCH + 1)) + NEW_VERSION="v$MAJOR.$MINOR.$PATCH" + fi + fi + + echo "New version will be: $NEW_VERSION" + echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT + + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ env.DOCKERHUB_USERNAME }} + password: ${{ env.DOCKERHUB_TOKEN }} + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: ./cloud/jenkins/docker + file: ./cloud/jenkins/docker/Dockerfile + platforms: linux/amd64,linux/arm64 + push: true + tags: | + ${{ env.DOCKER_PROJECT }}:latest + ${{ env.DOCKER_PROJECT }}:${{ steps.get_version.outputs.new_version }} diff --git a/cloud/jenkins/docker/Dockerfile b/cloud/jenkins/docker/Dockerfile new file mode 100644 index 0000000000..e142548bcc --- /dev/null +++ b/cloud/jenkins/docker/Dockerfile @@ -0,0 +1,66 @@ +FROM rockylinux:9 + +ENV ARCH="amd64" + +# Update & install base packages +RUN dnf -y update && \ + dnf -y install --nodocs wget unzip git curl tar zip which diffutils bc ca-certificates gnupg jq python3 --allowerasing && \ + dnf clean all && \ + curl -L "https://github.com/mikefarah/yq/releases/latest/download/yq_linux_${ARCH}" -o /usr/local/bin/yq && \ + chmod +x /usr/local/bin/yq + +# Install uv and dependencies +COPY pyproject.toml pyproject.toml +ENV PATH="/root/.local/bin:/root/.venv/bin:$PATH" +RUN curl -Ls https://astral.sh/uv/install.sh | bash && \ + uv venv .venv && \ + uv pip install -r pyproject.toml + +# Install Helm 3 - latest +RUN curl "https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3" | bash + +# Install kubectl - latest +RUN curl -sLO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/${ARCH}/kubectl" && \ + install -m 0755 kubectl /usr/local/bin/kubectl && \ + rm kubectl + +# Install krew and kuttl - latest +RUN curl -fsSLO "https://github.com/kubernetes-sigs/krew/releases/latest/download/krew-linux_${ARCH}.tar.gz" && \ + tar zxvf "krew-linux_${ARCH}.tar.gz" && \ + ./krew-linux_$ARCH install krew && \ + rm -rf "krew-linux_${ARCH}" "krew-linux_${ARCH}.tar.gz" +ENV PATH=$PATH:/root/.krew/bin +RUN kubectl krew install kuttl &&\ + kubectl krew install assert + +# Install kubectl-assert (via krew) +RUN curl -s https://raw.githubusercontent.com/gekoko/kubectl-assert/main/install.sh | bash && \ + mv $HOME/.krew/bin/kubectl-assert /usr/local/bin/ || true + +# Install eksctl - latest +RUN curl -sL "https://github.com/eksctl-io/eksctl/releases/latest/download/eksctl_$(uname -s)_${ARCH}.tar.gz" -o eksctl.tar.gz && \ + tar -xzf eksctl.tar.gz && \ + mv eksctl /usr/local/bin/eksctl && \ + chmod +x /usr/local/bin/eksctl && \ + rm -f eksctl.tar.gz + +# Install doctl - latest +RUN DO_LATEST=$(curl -s https://api.github.com/repos/digitalocean/doctl/releases/latest | jq -r '.tag_name') && \ + curl -sSL "https://github.com/digitalocean/doctl/releases/download/${DO_LATEST}/doctl-${DO_LATEST#v}-linux-${ARCH}.tar.gz" | tar -xz && \ + mv doctl /usr/local/bin/ && \ + chmod +x /usr/local/bin/doctl + +# Install Google Cloud SDK - latest +RUN GC_LATEST=$(curl -sSL https://dl.google.com/dl/cloudsdk/channels/rapid/components-2.json | jq -r '.version') && \ + curl -sSL "https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-cli-${GC_LATEST}-linux-x86_64.tar.gz" | tar -xz && \ + ./google-cloud-sdk/install.sh --quiet + +ENV PATH="/google-cloud-sdk/bin:$PATH" + +# Install Azure CLI - latest +RUN rpm --import https://packages.microsoft.com/keys/microsoft.asc && \ + curl -o /etc/yum.repos.d/azure-cli.repo https://packages.microsoft.com/config/rhel/9/prod.repo && \ + dnf install -y azure-cli && \ + dnf clean all + +ENTRYPOINT ["/bin/bash", "-c"] \ No newline at end of file diff --git a/cloud/jenkins/docker/pyproject.toml b/cloud/jenkins/docker/pyproject.toml new file mode 100644 index 0000000000..2a36287e68 --- /dev/null +++ b/cloud/jenkins/docker/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "psmdb-pytest" +version = "0.1.0" +description = "Tests for PSMDB Operator" +requires-python = ">=3.13" +dependencies = [ + "junitparser>=3.2.0", + "mypy>=1.16.0", + "pytest>=8.4.0", + "pytest-html>=4.1.1", + "pytest-html-merger>=0.1.0", + "pytest-json-report>=1.5.0", + "pyyaml>=6.0.2", + "ruff>=0.11.12", +] + +[tool.pytest.ini_options] +addopts = "--self-contained-html --json-report --json-report-file=e2e-tests/reports/report.json" +render_collapsed = "all" + +[[tool.mypy.overrides]] +module = ["pytest_html.*"] +follow_untyped_imports = true + +[tool.ruff] +line-length = 99 \ No newline at end of file From 1826a1e875d9ecb6f3420b8ae31bbc71c768ded5 Mon Sep 17 00:00:00 2001 From: Valmira Nogueira Date: Tue, 17 Jun 2025 10:09:43 -0300 Subject: [PATCH 2/5] Improve image size and remove uv dependencies --- .github/workflows/build-cloud-qa.yaml | 1 + cloud/jenkins/docker/Dockerfile | 57 ++++++++++++++------------- cloud/jenkins/docker/pyproject.toml | 26 ------------ 3 files changed, 30 insertions(+), 54 deletions(-) delete mode 100644 cloud/jenkins/docker/pyproject.toml diff --git a/.github/workflows/build-cloud-qa.yaml b/.github/workflows/build-cloud-qa.yaml index 567fb133f2..0af9a20266 100644 --- a/.github/workflows/build-cloud-qa.yaml +++ b/.github/workflows/build-cloud-qa.yaml @@ -3,6 +3,7 @@ name: Weekly Docker Image Build - perconalab/cloud-qa on: schedule: - cron: '0 3 * * 1' # Every Monday at 03:00 UTC + workflow_dispatch: jobs: build-and-push: diff --git a/cloud/jenkins/docker/Dockerfile b/cloud/jenkins/docker/Dockerfile index e142548bcc..5f3e107b4b 100644 --- a/cloud/jenkins/docker/Dockerfile +++ b/cloud/jenkins/docker/Dockerfile @@ -1,66 +1,67 @@ -FROM rockylinux:9 +FROM debian:bullseye-slim ENV ARCH="amd64" +ENV DEBIAN_FRONTEND=noninteractive +ENV PATH="/root/.local/bin:/root/.venv/bin:$PATH" + +# Install base tools +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + ca-certificates curl wget unzip git tar zip \ + python3 python3-venv python3-pip \ + jq gnupg diffutils bc && \ + apt-get clean && rm -rf /var/lib/apt/lists/* -# Update & install base packages -RUN dnf -y update && \ - dnf -y install --nodocs wget unzip git curl tar zip which diffutils bc ca-certificates gnupg jq python3 --allowerasing && \ - dnf clean all && \ - curl -L "https://github.com/mikefarah/yq/releases/latest/download/yq_linux_${ARCH}" -o /usr/local/bin/yq && \ +# yq +RUN curl -L "https://github.com/mikefarah/yq/releases/latest/download/yq_linux_${ARCH}" -o /usr/local/bin/yq && \ chmod +x /usr/local/bin/yq -# Install uv and dependencies -COPY pyproject.toml pyproject.toml -ENV PATH="/root/.local/bin:/root/.venv/bin:$PATH" +# Install uv RUN curl -Ls https://astral.sh/uv/install.sh | bash && \ - uv venv .venv && \ - uv pip install -r pyproject.toml + uv venv .venv -# Install Helm 3 - latest -RUN curl "https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3" | bash +# Helm 3 +RUN curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash -# Install kubectl - latest +# kubectl RUN curl -sLO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/${ARCH}/kubectl" && \ - install -m 0755 kubectl /usr/local/bin/kubectl && \ - rm kubectl + install -m 0755 kubectl /usr/local/bin/kubectl && rm kubectl -# Install krew and kuttl - latest +# krew + kuttl + assert RUN curl -fsSLO "https://github.com/kubernetes-sigs/krew/releases/latest/download/krew-linux_${ARCH}.tar.gz" && \ tar zxvf "krew-linux_${ARCH}.tar.gz" && \ ./krew-linux_$ARCH install krew && \ rm -rf "krew-linux_${ARCH}" "krew-linux_${ARCH}.tar.gz" ENV PATH=$PATH:/root/.krew/bin -RUN kubectl krew install kuttl &&\ +RUN kubectl krew install kuttl && \ kubectl krew install assert -# Install kubectl-assert (via krew) +# kubectl-assert RUN curl -s https://raw.githubusercontent.com/gekoko/kubectl-assert/main/install.sh | bash && \ mv $HOME/.krew/bin/kubectl-assert /usr/local/bin/ || true -# Install eksctl - latest +# EKS CLI RUN curl -sL "https://github.com/eksctl-io/eksctl/releases/latest/download/eksctl_$(uname -s)_${ARCH}.tar.gz" -o eksctl.tar.gz && \ tar -xzf eksctl.tar.gz && \ mv eksctl /usr/local/bin/eksctl && \ chmod +x /usr/local/bin/eksctl && \ rm -f eksctl.tar.gz -# Install doctl - latest +# Digital Ocean CLI RUN DO_LATEST=$(curl -s https://api.github.com/repos/digitalocean/doctl/releases/latest | jq -r '.tag_name') && \ curl -sSL "https://github.com/digitalocean/doctl/releases/download/${DO_LATEST}/doctl-${DO_LATEST#v}-linux-${ARCH}.tar.gz" | tar -xz && \ mv doctl /usr/local/bin/ && \ chmod +x /usr/local/bin/doctl -# Install Google Cloud SDK - latest +# Google Cloud SDK RUN GC_LATEST=$(curl -sSL https://dl.google.com/dl/cloudsdk/channels/rapid/components-2.json | jq -r '.version') && \ curl -sSL "https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-cli-${GC_LATEST}-linux-x86_64.tar.gz" | tar -xz && \ ./google-cloud-sdk/install.sh --quiet - ENV PATH="/google-cloud-sdk/bin:$PATH" -# Install Azure CLI - latest -RUN rpm --import https://packages.microsoft.com/keys/microsoft.asc && \ - curl -o /etc/yum.repos.d/azure-cli.repo https://packages.microsoft.com/config/rhel/9/prod.repo && \ - dnf install -y azure-cli && \ - dnf clean all +# Azure CLI +RUN curl -sL https://aka.ms/InstallAzureCLIDeb | bash +# Enforce bash by default +RUN ln -sf /bin/bash /bin/sh ENTRYPOINT ["/bin/bash", "-c"] \ No newline at end of file diff --git a/cloud/jenkins/docker/pyproject.toml b/cloud/jenkins/docker/pyproject.toml deleted file mode 100644 index 2a36287e68..0000000000 --- a/cloud/jenkins/docker/pyproject.toml +++ /dev/null @@ -1,26 +0,0 @@ -[project] -name = "psmdb-pytest" -version = "0.1.0" -description = "Tests for PSMDB Operator" -requires-python = ">=3.13" -dependencies = [ - "junitparser>=3.2.0", - "mypy>=1.16.0", - "pytest>=8.4.0", - "pytest-html>=4.1.1", - "pytest-html-merger>=0.1.0", - "pytest-json-report>=1.5.0", - "pyyaml>=6.0.2", - "ruff>=0.11.12", -] - -[tool.pytest.ini_options] -addopts = "--self-contained-html --json-report --json-report-file=e2e-tests/reports/report.json" -render_collapsed = "all" - -[[tool.mypy.overrides]] -module = ["pytest_html.*"] -follow_untyped_imports = true - -[tool.ruff] -line-length = 99 \ No newline at end of file From c391af933ecfdea9b080fd7ba4b5e2fc87561825 Mon Sep 17 00:00:00 2001 From: Valmira Nogueira Date: Thu, 18 Sep 2025 18:06:44 -0300 Subject: [PATCH 3/5] Update image with new components and fix some comments --- cloud/jenkins/docker/Dockerfile | 113 +++++++++++++++++--------------- 1 file changed, 60 insertions(+), 53 deletions(-) diff --git a/cloud/jenkins/docker/Dockerfile b/cloud/jenkins/docker/Dockerfile index 5f3e107b4b..4e75d5687c 100644 --- a/cloud/jenkins/docker/Dockerfile +++ b/cloud/jenkins/docker/Dockerfile @@ -1,67 +1,74 @@ FROM debian:bullseye-slim -ENV ARCH="amd64" +ARG TARGETARCH ENV DEBIAN_FRONTEND=noninteractive -ENV PATH="/root/.local/bin:/root/.venv/bin:$PATH" +ENV HOME=/home/jenkins +ENV PATH="$HOME/.local/bin:$HOME/.venv/bin:$HOME/google-cloud-sdk/bin:$PATH" +ENV CLOUDSDK_CORE_DISABLE_PROMPTS=1 +WORKDIR $HOME -# Install base tools +# Base dependencies RUN apt-get update && \ apt-get install -y --no-install-recommends \ - ca-certificates curl wget unzip git tar zip \ - python3 python3-venv python3-pip \ - jq gnupg diffutils bc && \ + sudo bash curl wget tar unzip git python3 python3-venv python3-pip jq gnupg ca-certificates docker.io && \ + ln -sf /bin/bash /bin/sh && \ + curl -L "https://github.com/mikefarah/yq/releases/latest/download/yq_linux_${TARGETARCH}" -o /usr/local/bin/yq && chmod +x /usr/local/bin/yq && \ apt-get clean && rm -rf /var/lib/apt/lists/* -# yq -RUN curl -L "https://github.com/mikefarah/yq/releases/latest/download/yq_linux_${ARCH}" -o /usr/local/bin/yq && \ - chmod +x /usr/local/bin/yq +# Jenkins user +RUN useradd -u 1000 -m jenkins && \ + echo "jenkins ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers && \ + mkdir -p /home/jenkins && \ + chown -R jenkins:jenkins /home/jenkins +USER jenkins -# Install uv -RUN curl -Ls https://astral.sh/uv/install.sh | bash && \ - uv venv .venv +# Install yq, uv, Helm, kubectl, kuttl, kubectl-assert, +RUN set -euo pipefail && \ + # uv + curl -Ls https://astral.sh/uv/install.sh | bash && uv venv "$HOME/.venv" && \ + # Helm + HELM_VERSION="$(curl -sSL https://api.github.com/repos/helm/helm/releases/latest | jq -r '.tag_name')" && \ + curl -fsSL -o helm.tar.gz "https://get.helm.sh/helm-${HELM_VERSION}-linux-${TARGETARCH}.tar.gz" && \ + tar -xzf helm.tar.gz && mv linux-${TARGETARCH}/helm "$HOME/.local/bin/helm" && rm -rf helm.tar.gz "linux-${TARGETARCH}" && helm version --client && \ + # kubectl + KUBECTL_VERSION="$(curl -L -s https://dl.k8s.io/release/stable.txt)" && \ + curl -sLO "https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/${TARGETARCH}/kubectl" && \ + install -m 0755 kubectl "$HOME/.local/bin/kubectl" && rm kubectl && kubectl version --client && \ + # kuttl + KUTTL_VERSION="$(curl -s https://api.github.com/repos/kudobuilder/kuttl/releases/latest | jq -r .tag_name)" && \ + KUTTL_ARCH="${TARGETARCH/amd64/x86_64}" && \ + curl -sLo kubectl-kuttl "https://github.com/kudobuilder/kuttl/releases/download/${KUTTL_VERSION}/kubectl-kuttl_${KUTTL_VERSION#v}_linux_${KUTTL_ARCH}" && \ + chmod +x kubectl-kuttl && mv kubectl-kuttl "$HOME/.local/bin/" && kubectl kuttl --version && \ + # kubectl-assert + curl -Lo kubectl-assert https://raw.githubusercontent.com/morningspace/kubeassert/master/kubectl-assert.sh && \ + chmod +x kubectl-assert && mv kubectl-assert "$HOME/.local/bin/" && kubectl assert --version -# Helm 3 -RUN curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash - -# kubectl -RUN curl -sLO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/${ARCH}/kubectl" && \ - install -m 0755 kubectl /usr/local/bin/kubectl && rm kubectl - -# krew + kuttl + assert -RUN curl -fsSLO "https://github.com/kubernetes-sigs/krew/releases/latest/download/krew-linux_${ARCH}.tar.gz" && \ - tar zxvf "krew-linux_${ARCH}.tar.gz" && \ - ./krew-linux_$ARCH install krew && \ - rm -rf "krew-linux_${ARCH}" "krew-linux_${ARCH}.tar.gz" -ENV PATH=$PATH:/root/.krew/bin -RUN kubectl krew install kuttl && \ - kubectl krew install assert - -# kubectl-assert -RUN curl -s https://raw.githubusercontent.com/gekoko/kubectl-assert/main/install.sh | bash && \ - mv $HOME/.krew/bin/kubectl-assert /usr/local/bin/ || true - -# EKS CLI -RUN curl -sL "https://github.com/eksctl-io/eksctl/releases/latest/download/eksctl_$(uname -s)_${ARCH}.tar.gz" -o eksctl.tar.gz && \ - tar -xzf eksctl.tar.gz && \ - mv eksctl /usr/local/bin/eksctl && \ - chmod +x /usr/local/bin/eksctl && \ - rm -f eksctl.tar.gz - -# Digital Ocean CLI -RUN DO_LATEST=$(curl -s https://api.github.com/repos/digitalocean/doctl/releases/latest | jq -r '.tag_name') && \ - curl -sSL "https://github.com/digitalocean/doctl/releases/download/${DO_LATEST}/doctl-${DO_LATEST#v}-linux-${ARCH}.tar.gz" | tar -xz && \ - mv doctl /usr/local/bin/ && \ - chmod +x /usr/local/bin/doctl - -# Google Cloud SDK -RUN GC_LATEST=$(curl -sSL https://dl.google.com/dl/cloudsdk/channels/rapid/components-2.json | jq -r '.version') && \ +# Install clients: eksctl, doctl, gcloud +RUN set -euo pipefail && \ + echo "Installing AWS client" && \ + EKS_VERSION=$(curl -s https://api.github.com/repos/eksctl-io/eksctl/releases/latest | jq -r .tag_name) && \ + curl -sL "https://github.com/eksctl-io/eksctl/releases/download/${EKS_VERSION}/eksctl_$(uname -s)_${TARGETARCH}.tar.gz" | tar -xz && \ + mv eksctl "$HOME/.local/bin/eksctl" && chmod +x "$HOME/.local/bin/eksctl" && eksctl version && \ + echo "Installing Digital Ocean client" && \ + DO_LATEST=$(curl -s https://api.github.com/repos/digitalocean/doctl/releases/latest | jq -r '.tag_name') && \ + curl -sSL "https://github.com/digitalocean/doctl/releases/download/${DO_LATEST}/doctl-${DO_LATEST#v}-linux-${TARGETARCH}.tar.gz" | tar -xz && \ + mv doctl "$HOME/.local/bin/" && chmod +x "$HOME/.local/bin/doctl" && doctl version && \ + echo "Installing Google client" && \ + GC_LATEST=$(curl -sSL https://dl.google.com/dl/cloudsdk/channels/rapid/components-2.json | jq -r '.version') && \ curl -sSL "https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-cli-${GC_LATEST}-linux-x86_64.tar.gz" | tar -xz && \ - ./google-cloud-sdk/install.sh --quiet -ENV PATH="/google-cloud-sdk/bin:$PATH" + ./google-cloud-sdk/install.sh --quiet && \ + ./google-cloud-sdk/bin/gcloud components install gke-gcloud-auth-plugin --quiet && gcloud --version -# Azure CLI -RUN curl -sL https://aka.ms/InstallAzureCLIDeb | bash +# Azure cli requires root +USER root +RUN echo "Installing Azure client" && \ + curl -sL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /etc/apt/trusted.gpg.d/microsoft.gpg && \ + AZ_REPO=$(grep VERSION_CODENAME= /etc/os-release | cut -d= -f2) && \ + echo "deb [arch=$(dpkg --print-architecture)] https://packages.microsoft.com/repos/azure-cli/ $AZ_REPO main" > /etc/apt/sources.list.d/azure-cli.list && \ + apt-get update && apt-get install -y --no-install-recommends azure-cli && \ + apt-get clean && rm -rf /var/lib/apt/lists/* -# Enforce bash by default -RUN ln -sf /bin/bash /bin/sh +USER jenkins +WORKDIR /home/jenkins +ENV PATH="$HOME/.local/bin:$HOME/.venv/bin:$HOME/google-cloud-sdk/bin:$PATH" ENTRYPOINT ["/bin/bash", "-c"] \ No newline at end of file From eceaf641d99cdf5f80158e1c47dc391f31820994 Mon Sep 17 00:00:00 2001 From: Valmira Nogueira Date: Fri, 19 Sep 2025 23:00:02 -0300 Subject: [PATCH 4/5] Add checksum verification --- cloud/jenkins/docker/Dockerfile | 80 +++++++++++++--------- cloud/jenkins/docker/install_dependency.sh | 53 ++++++++++++++ 2 files changed, 100 insertions(+), 33 deletions(-) create mode 100755 cloud/jenkins/docker/install_dependency.sh diff --git a/cloud/jenkins/docker/Dockerfile b/cloud/jenkins/docker/Dockerfile index 4e75d5687c..a1f6b620e8 100644 --- a/cloud/jenkins/docker/Dockerfile +++ b/cloud/jenkins/docker/Dockerfile @@ -2,10 +2,10 @@ FROM debian:bullseye-slim ARG TARGETARCH ENV DEBIAN_FRONTEND=noninteractive -ENV HOME=/home/jenkins -ENV PATH="$HOME/.local/bin:$HOME/.venv/bin:$HOME/google-cloud-sdk/bin:$PATH" +ENV HOME=/home/clouduser +ENV PATH="${HOME}/.local/bin:${HOME}/.venv/bin:${HOME}/.local/bin/google-cloud-sdk/bin:${PATH}" ENV CLOUDSDK_CORE_DISABLE_PROMPTS=1 -WORKDIR $HOME +WORKDIR "${HOME}" # Base dependencies RUN apt-get update && \ @@ -15,49 +15,63 @@ RUN apt-get update && \ curl -L "https://github.com/mikefarah/yq/releases/latest/download/yq_linux_${TARGETARCH}" -o /usr/local/bin/yq && chmod +x /usr/local/bin/yq && \ apt-get clean && rm -rf /var/lib/apt/lists/* -# Jenkins user -RUN useradd -u 1000 -m jenkins && \ - echo "jenkins ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers && \ - mkdir -p /home/jenkins && \ - chown -R jenkins:jenkins /home/jenkins -USER jenkins +# Cloud user +RUN useradd -u 1000 -m clouduser && \ + echo "clouduser ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers && \ + mkdir -p "${HOME}/.local/bin" && \ + chown -R clouduser:clouduser /home/clouduser +USER clouduser + +# Create a checksum verifier for downloaded files +COPY --chmod=755 install_dependency.sh $HOME/.local/bin/install_dependency # Install yq, uv, Helm, kubectl, kuttl, kubectl-assert, RUN set -euo pipefail && \ # uv - curl -Ls https://astral.sh/uv/install.sh | bash && uv venv "$HOME/.venv" && \ + UV_LATEST="$(curl -s https://api.github.com/repos/astral-sh/uv/releases/latest | jq -r .tag_name)" && \ + UV_ARCH="${TARGETARCH/amd64/x86_64}" && UV_ARCH="${UV_ARCH/arm64/aarch64}" && \ + install_dependency "https://github.com/astral-sh/uv/releases/download/${UV_LATEST}/uv-${UV_ARCH}-unknown-linux-gnu.tar.gz" && \ + uv --version && \ # Helm HELM_VERSION="$(curl -sSL https://api.github.com/repos/helm/helm/releases/latest | jq -r '.tag_name')" && \ - curl -fsSL -o helm.tar.gz "https://get.helm.sh/helm-${HELM_VERSION}-linux-${TARGETARCH}.tar.gz" && \ - tar -xzf helm.tar.gz && mv linux-${TARGETARCH}/helm "$HOME/.local/bin/helm" && rm -rf helm.tar.gz "linux-${TARGETARCH}" && helm version --client && \ + install_dependency "https://get.helm.sh/helm-${HELM_VERSION}-linux-${TARGETARCH}.tar.gz" && \ + helm version --client && \ # kubectl KUBECTL_VERSION="$(curl -L -s https://dl.k8s.io/release/stable.txt)" && \ - curl -sLO "https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/${TARGETARCH}/kubectl" && \ - install -m 0755 kubectl "$HOME/.local/bin/kubectl" && rm kubectl && kubectl version --client && \ - # kuttl + install_dependency "https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/${TARGETARCH}/kubectl" && \ + kubectl version --client && \ + # kubectl-assert - has no published checksum KUTTL_VERSION="$(curl -s https://api.github.com/repos/kudobuilder/kuttl/releases/latest | jq -r .tag_name)" && \ KUTTL_ARCH="${TARGETARCH/amd64/x86_64}" && \ - curl -sLo kubectl-kuttl "https://github.com/kudobuilder/kuttl/releases/download/${KUTTL_VERSION}/kubectl-kuttl_${KUTTL_VERSION#v}_linux_${KUTTL_ARCH}" && \ - chmod +x kubectl-kuttl && mv kubectl-kuttl "$HOME/.local/bin/" && kubectl kuttl --version && \ - # kubectl-assert - curl -Lo kubectl-assert https://raw.githubusercontent.com/morningspace/kubeassert/master/kubectl-assert.sh && \ - chmod +x kubectl-assert && mv kubectl-assert "$HOME/.local/bin/" && kubectl assert --version + KUTTL_CHECKSUM="https://github.com/kudobuilder/kuttl/releases/download/${KUTTL_VERSION}/checksums.txt" && \ + KUTTL_FILENAME="kubectl-kuttl_${KUTTL_VERSION#v}_linux_${KUTTL_ARCH}" && \ + install_dependency "https://github.com/kudobuilder/kuttl/releases/download/${KUTTL_VERSION}/${KUTTL_FILENAME}" "1" "${KUTTL_CHECKSUM}" && \ + mv "$HOME/.local/bin/$KUTTL_FILENAME" "$HOME/.local/bin/kubectl-kuttl" && \ + kubectl-kuttl --version && \ + # kubectl-assert - has no published checksum + install_dependency "https://raw.githubusercontent.com/morningspace/kubeassert/master/kubectl-assert.sh" "0" && \ + mv "$HOME/.local/bin/kubectl-assert.sh" "$HOME/.local/bin/kubectl-assert" && \ + kubectl-assert --version # Install clients: eksctl, doctl, gcloud RUN set -euo pipefail && \ - echo "Installing AWS client" && \ + # AWS client EKS_VERSION=$(curl -s https://api.github.com/repos/eksctl-io/eksctl/releases/latest | jq -r .tag_name) && \ - curl -sL "https://github.com/eksctl-io/eksctl/releases/download/${EKS_VERSION}/eksctl_$(uname -s)_${TARGETARCH}.tar.gz" | tar -xz && \ - mv eksctl "$HOME/.local/bin/eksctl" && chmod +x "$HOME/.local/bin/eksctl" && eksctl version && \ - echo "Installing Digital Ocean client" && \ + EKS_CHECKSUM="https://github.com/eksctl-io/eksctl/releases/download/${EKS_VERSION}/eksctl_checksums.txt" && \ + EKS_FILENAME="eksctl_linux_${TARGETARCH}.tar.gz" && \ + install_dependency "https://github.com/eksctl-io/eksctl/releases/download/${EKS_VERSION}/$EKS_FILENAME" "1" "${EKS_CHECKSUM}" "0" && \ + chmod +x "${HOME}/.local/bin/eksctl" && eksctl version && \ + # Digital Ocean client DO_LATEST=$(curl -s https://api.github.com/repos/digitalocean/doctl/releases/latest | jq -r '.tag_name') && \ - curl -sSL "https://github.com/digitalocean/doctl/releases/download/${DO_LATEST}/doctl-${DO_LATEST#v}-linux-${TARGETARCH}.tar.gz" | tar -xz && \ - mv doctl "$HOME/.local/bin/" && chmod +x "$HOME/.local/bin/doctl" && doctl version && \ - echo "Installing Google client" && \ + DO_CHECKSUM="https://github.com/digitalocean/doctl/releases/download/${DO_LATEST}/doctl-${DO_LATEST#v}-checksums.sha256" && \ + DO_FILENAME="doctl-${DO_LATEST#v}-linux-${TARGETARCH}.tar.gz" && \ + install_dependency "https://github.com/digitalocean/doctl/releases/download/${DO_LATEST}/${DO_FILENAME}" "1" "${DO_CHECKSUM}" "0" && \ + chmod +x "${HOME}/.local/bin/doctl" && doctl version && \ + # Google client GC_LATEST=$(curl -sSL https://dl.google.com/dl/cloudsdk/channels/rapid/components-2.json | jq -r '.version') && \ - curl -sSL "https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-cli-${GC_LATEST}-linux-x86_64.tar.gz" | tar -xz && \ - ./google-cloud-sdk/install.sh --quiet && \ - ./google-cloud-sdk/bin/gcloud components install gke-gcloud-auth-plugin --quiet && gcloud --version + install_dependency "https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-cli-${GC_LATEST}-linux-x86_64.tar.gz" "0" "" "0" && \ + "${HOME}/.local/bin/google-cloud-sdk/install.sh" --quiet && \ + "${HOME}/.local/bin/google-cloud-sdk/bin/gcloud" components install gke-gcloud-auth-plugin --quiet && gcloud --version # Azure cli requires root USER root @@ -68,7 +82,7 @@ RUN echo "Installing Azure client" && \ apt-get update && apt-get install -y --no-install-recommends azure-cli && \ apt-get clean && rm -rf /var/lib/apt/lists/* -USER jenkins -WORKDIR /home/jenkins -ENV PATH="$HOME/.local/bin:$HOME/.venv/bin:$HOME/google-cloud-sdk/bin:$PATH" +USER clouduser +WORKDIR /home/clouduser +ENV PATH="${HOME}/.local/bin:${HOME}/.venv/bin:${HOME}/.local/bin/google-cloud-sdk/bin:${PATH}" ENTRYPOINT ["/bin/bash", "-c"] \ No newline at end of file diff --git a/cloud/jenkins/docker/install_dependency.sh b/cloud/jenkins/docker/install_dependency.sh new file mode 100755 index 0000000000..c7452dc96d --- /dev/null +++ b/cloud/jenkins/docker/install_dependency.sh @@ -0,0 +1,53 @@ +#!/bin/bash +set -euo pipefail + +url="$1" +verify="${2:-1}" +checksum_url="${3:-}" +strip_components="${4:-1}" + +file="$(basename "$url")" +bin_folder="$HOME/.local/bin" +verified_checksum=0 + +verify_checksum() { + local local_checksum_url="$1" + local checksum_file="checksum_file" + if curl -fsSL "$local_checksum_url" -o "$checksum_file"; then + if grep -q " " "$checksum_file"; then + new_checksum=$(grep -i "$(basename "$url")" "$checksum_file" | awk '{print $1}') + echo "$new_checksum" > "$checksum_file" + fi + echo "$(cat $checksum_file) $file" > "$checksum_file" + echo "Filtered checksum file is: $(cat $checksum_file)" + sha256sum -c "$checksum_file" && verified_checksum=1 + fi +} + +checksum_verification() { + echo "Verifying checksum" + if [[ -n "$checksum_url" ]]; then + verify_checksum "$checksum_url" + else + for type in sha256 sha256sum sha256.txt; do + verify_checksum "$url.$type" + [[ $verified_checksum -eq 1 ]] && break + done + fi + [[ $verified_checksum -eq 1 ]] && echo "Checksum verified" || { echo "Checksum mismatch!"; exit 1; } +} + +echo "Downloading $url" +curl -fsSL "$url" -o "$file" +[[ ! -f "$file" ]] && echo "File not downloaded!" && exit 1 +[[ "$verify" == "1" ]] && checksum_verification + +mkdir -p "$bin_folder" +if [[ "$file" == *.tar.gz ]]; then + echo "Extracting $file → $bin_folder" + tar -xzf "$file" -C "$bin_folder" --strip-components="$strip_components" + echo "Extracted into $bin_folder" +else + echo "Installing $file → $bin_folder" + mv "$file" "$bin_folder/" && chmod 755 "$bin_folder/$file" +fi From 9bb49ecd794a7cabbda05b87f039cd64990b4c74 Mon Sep 17 00:00:00 2001 From: Valmira Nogueira Date: Mon, 22 Sep 2025 09:58:46 -0300 Subject: [PATCH 5/5] Add minikube --- cloud/jenkins/docker/Dockerfile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cloud/jenkins/docker/Dockerfile b/cloud/jenkins/docker/Dockerfile index a1f6b620e8..a88f546756 100644 --- a/cloud/jenkins/docker/Dockerfile +++ b/cloud/jenkins/docker/Dockerfile @@ -71,7 +71,10 @@ RUN set -euo pipefail && \ GC_LATEST=$(curl -sSL https://dl.google.com/dl/cloudsdk/channels/rapid/components-2.json | jq -r '.version') && \ install_dependency "https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-cli-${GC_LATEST}-linux-x86_64.tar.gz" "0" "" "0" && \ "${HOME}/.local/bin/google-cloud-sdk/install.sh" --quiet && \ - "${HOME}/.local/bin/google-cloud-sdk/bin/gcloud" components install gke-gcloud-auth-plugin --quiet && gcloud --version + "${HOME}/.local/bin/google-cloud-sdk/bin/gcloud" components install gke-gcloud-auth-plugin --quiet && gcloud --version && \ + # Minikube + install_dependency "https://storage.googleapis.com/minikube/releases/latest/minikube-linux-${TARGETARCH}" && \ + mv "$HOME/.local/bin/minikube-linux-${TARGETARCH}" "$HOME/.local/bin/minikube" && minikube version # Azure cli requires root USER root