Fix e2e runner missing docker CLI on Debian trixie#20
Conversation
Co-authored-by: tg123 <170430+tg123@users.noreply.github.com>
Co-authored-by: tg123 <170430+tg123@users.noreply.github.com>
|
@copilot could you please take a look at https://github.com/tg123/sshpiper/tree/master/e2e |
Co-authored-by: tg123 <170430+tg123@users.noreply.github.com>
Done in commit 3e740ad. I split e2e into a separate workflow (.github/workflows/e2e.yml), switched docker e2e setup to Docker Compose (.github/e2e/docker-compose.yml), and kept kube coverage in that e2e pipeline via the kube-sshd smoke check. |
Co-authored-by: tg123 <170430+tg123@users.noreply.github.com>
Co-authored-by: tg123 <170430+tg123@users.noreply.github.com>
| - name: Build test binaries | ||
| run: | | ||
| mkdir -p /tmp/bin | ||
| go build -o /tmp/bin/docker-sshd ./cmd/docker-sshd |
There was a problem hiding this comment.
@copilot move go build and go test into a container of docker compose, so users can test all by themselves
There was a problem hiding this comment.
Done in commit 6d0c2c1. go build and go test now run inside the docker compose e2e-runner container (e2e/docker-compose.yml), and the workflow now invokes that compose runner after kind setup.
Co-authored-by: tg123 <170430+tg123@users.noreply.github.com>
|
Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details. |
|
@copilot fix lint |
Co-authored-by: tg123 <170430+tg123@users.noreply.github.com>
|
Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details. |
Co-authored-by: tg123 <170430+tg123@users.noreply.github.com>
|
Lets setup kind inside docker compose to avoid host network You can copy sshpiper kind setup @copilot |
Co-authored-by: tg123 <170430+tg123@users.noreply.github.com>
Implemented in commit 68cb597. I moved kind create/export/delete into the compose runner flow (based on the sshpiper approach), so e2e runs without host network dependency. Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
@copilot fix e2e |
There was a problem hiding this comment.
Pull request overview
Sets up a dedicated, Docker Compose runner-based CI E2E pipeline for docker-sshd and kube-sshd, including spinning up a Kind Kubernetes cluster inside the compose runner.
Changes:
- Added a new GitHub Actions workflow to run E2E via Docker Compose (
.github/workflows/e2e.yml) and removed the previous E2E smoke checks fromtests.yml. - Introduced compose-driven E2E orchestration under
e2e/, including a dedicated test runner image and services. - Added Go-based E2E tests covering both the Docker and Kubernetes execution paths.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| e2e/e2e_test.go | Adds Docker/Kubernetes E2E tests that start the binaries and verify SSH execution behavior. |
| e2e/docker-compose.yml | Defines the compose services for an E2E target container and a privileged runner that builds binaries, creates Kind, and runs tests. |
| e2e/Dockerfile.testrunner | Creates the runner image with Go, SSH client, Docker CLI, kubectl, and Kind. |
| .github/workflows/tests.yml | Removes prior E2E smoke job, leaving unit tests only. |
| .github/workflows/e2e.yml | Adds dedicated E2E workflow that runs compose-based E2E in CI. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| cmd := exec.Command(bin, "--address", "127.0.0.1", "--port", "2232", "--server-key", key) | ||
| cmd.Stdout = os.Stdout | ||
| cmd.Stderr = os.Stderr | ||
| if err := cmd.Start(); err != nil { | ||
| t.Fatalf("start docker-sshd: %v", err) | ||
| } | ||
| defer func() { | ||
| _ = cmd.Process.Kill() | ||
| _, _ = cmd.Process.Wait() | ||
| }() | ||
|
|
||
| out := retrySSH(t, "2232", container+"@127.0.0.1") | ||
| if !hasOKLine(out) { |
There was a problem hiding this comment.
The tests bind docker-sshd/kube-sshd to fixed ports 2232 and 2233. If those ports are already in use on the runner (or if tests ever run concurrently), the tests will fail even when the code is correct. Consider selecting an ephemeral free port (e.g., by binding a listener to 127.0.0.1:0, reading the chosen port, then starting the process with that port).
| environment: | ||
| - KUBECONFIG=/root/.kube/config | ||
| volumes: | ||
| - ..:/src | ||
| - /var/run/docker.sock:/var/run/docker.sock | ||
| - ${KUBECONFIG:-/tmp/invalid-kubeconfig-path}:/root/.kube/config:ro | ||
| command: | ||
| - /bin/sh | ||
| - -ec | ||
| - | | ||
| export GOFLAGS=-buildvcs=false | ||
| mkdir -p /tmp/bin | ||
| go build -o /tmp/bin/docker-sshd ./cmd/docker-sshd | ||
| go build -o /tmp/bin/kube-sshd ./cmd/kube-sshd | ||
| if [ "$${KUBE_SSHD_E2E:-1}" = "1" ]; then | ||
| kind get clusters | grep -qx docker-sshd-e2e || kind create cluster --name docker-sshd-e2e | ||
| kind export kubeconfig --name docker-sshd-e2e --internal | ||
| kubectl wait --for=condition=Ready pod -n kube-system --all --timeout=2m |
There was a problem hiding this comment.
kind export kubeconfig writes to $KUBECONFIG (set to /root/.kube/config), but that path is bind-mounted read-only from the host (:ro). On CI where KUBECONFIG is typically unset, Docker will also create /tmp/invalid-kubeconfig-path as a directory and mount it onto /root/.kube/config, which will cause kind export kubeconfig/kubectl to fail. Consider removing this volume mount by default (let the runner generate its own kubeconfig), or mount a writable file path and only override it via a separate compose override/profile for local runs.
| command: | ||
| - /bin/sh | ||
| - -ec | ||
| - | | ||
| export GOFLAGS=-buildvcs=false | ||
| mkdir -p /tmp/bin | ||
| go build -o /tmp/bin/docker-sshd ./cmd/docker-sshd | ||
| go build -o /tmp/bin/kube-sshd ./cmd/kube-sshd | ||
| if [ "$${KUBE_SSHD_E2E:-1}" = "1" ]; then | ||
| kind get clusters | grep -qx docker-sshd-e2e || kind create cluster --name docker-sshd-e2e | ||
| kind export kubeconfig --name docker-sshd-e2e --internal | ||
| kubectl wait --for=condition=Ready pod -n kube-system --all --timeout=2m | ||
| fi | ||
| DOCKER_SSHD_E2E=$${DOCKER_SSHD_E2E:-1} \ | ||
| KUBE_SSHD_E2E=$${KUBE_SSHD_E2E:-1} \ | ||
| DOCKER_SSHD_BIN=/tmp/bin/docker-sshd \ | ||
| KUBE_SSHD_BIN=/tmp/bin/kube-sshd \ | ||
| go test ./e2e -v | ||
| if [ "$${KUBE_SSHD_E2E:-1}" = "1" ]; then | ||
| kind delete cluster --name docker-sshd-e2e || true | ||
| fi |
There was a problem hiding this comment.
Because the shell runs with -e, if go test ./e2e fails the script will exit before the kind delete cluster block runs, leaving Kind containers/networks behind (especially noticeable on self-hosted/local runners). Use a trap inside this script to always delete the cluster on EXIT, or temporarily disable -e around go test and ensure cleanup runs in all cases.
|
|
||
| RUN apt-get update && apt-get install -y --no-install-recommends openssh-client curl ca-certificates docker.io && rm -rf /var/lib/apt/lists/* \ | ||
| && curl -fsSL https://dl.k8s.io/release/v1.34.1/bin/linux/amd64/kubectl -o /usr/local/bin/kubectl \ | ||
| && GOBIN=/usr/local/bin go install sigs.k8s.io/kind@v0.30.0 \ | ||
| && chmod +x /usr/local/bin/kubectl |
There was a problem hiding this comment.
The Dockerfile hardcodes downloading kubectl for linux/amd64, which will break the runner image build on ARM64 hosts (e.g., Apple Silicon) and any non-amd64 CI. Also, the direct curl download is not integrity-verified. Consider using ARG TARGETARCH (BuildKit) to select the correct kubectl binary, and verify the download via the published SHA256 (or install via a trusted package source).
| RUN apt-get update && apt-get install -y --no-install-recommends openssh-client curl ca-certificates docker.io && rm -rf /var/lib/apt/lists/* \ | |
| && curl -fsSL https://dl.k8s.io/release/v1.34.1/bin/linux/amd64/kubectl -o /usr/local/bin/kubectl \ | |
| && GOBIN=/usr/local/bin go install sigs.k8s.io/kind@v0.30.0 \ | |
| && chmod +x /usr/local/bin/kubectl | |
| ARG TARGETARCH | |
| RUN apt-get update && apt-get install -y --no-install-recommends openssh-client curl ca-certificates docker.io && rm -rf /var/lib/apt/lists/* \ | |
| && KUBECTL_VERSION=v1.34.1 \ | |
| && KUBECTL_ARCH="${TARGETARCH:-amd64}" \ | |
| && curl -fsSL "https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/${KUBECTL_ARCH}/kubectl" -o /tmp/kubectl \ | |
| && curl -fsSL "https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/${KUBECTL_ARCH}/kubectl.sha256" -o /tmp/kubectl.sha256 \ | |
| && echo "$(cat /tmp/kubectl.sha256) /tmp/kubectl" | sha256sum -c - \ | |
| && install -m 0755 /tmp/kubectl /usr/local/bin/kubectl \ | |
| && rm -f /tmp/kubectl /tmp/kubectl.sha256 \ | |
| && GOBIN=/usr/local/bin go install sigs.k8s.io/kind@v0.30.0 |
The e2e workflow failed because
kindcould not create its cluster inside the runner container:On Debian trixie (the
golang:1.26base), thedocker.iopackage ships only the daemon; thedockerCLI now lives in the separatedocker-clipackage, which is merely aRecommends. Combined with--no-install-recommends, the CLI was never installed, whilekindshells out to it.Changes
e2e/Dockerfile.testrunner: installdocker-cliinstead ofdocker.io. The runner needs only the client, as it targets the mounted host/var/run/docker.sockrather than running its own daemon.💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.