From 7135abb2c9fe0f7207f4b063b6cf43d40557dc73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?plaf=C3=BC?= Date: Fri, 27 Dec 2024 16:25:55 +0100 Subject: [PATCH] Add docker in docker example to advanced usage in docs (#4620) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Patrick Schratz --- .cspell.json | 1 + docs/docs/20-usage/90-advanced-usage.md | 93 +++++++++++++++++++ .../version-2.8/20-usage/90-advanced-usage.md | 90 ++++++++++++++++++ 3 files changed, 184 insertions(+) diff --git a/.cspell.json b/.cspell.json index 68a768057..419c4e0db 100644 --- a/.cspell.json +++ b/.cspell.json @@ -39,6 +39,7 @@ "cpuset", "creativecommons", "Curr", + "CERTDIR", "datacenter", "DATASOURCE", "Debugf", diff --git a/docs/docs/20-usage/90-advanced-usage.md b/docs/docs/20-usage/90-advanced-usage.md index 910646629..e8a691de0 100644 --- a/docs/docs/20-usage/90-advanced-usage.md +++ b/docs/docs/20-usage/90-advanced-usage.md @@ -127,3 +127,96 @@ WOODPECKER_ENVIRONMENT=first_var:value1,second_var:value2 ``` Note that this tightly couples the server and app configurations (where the app is a completely separate application). But this is a good option for truly global variables which should apply to all steps in all pipelines for all apps. + +## Docker in docker (dind) setup + +:::warning +This set up will only work on trusted repositories and for security reasons should only be used in private environments. +See [project settings](./75-project-settings.md#trusted) to enable "trusted" mode. +::: + +The snippet below shows how a step can communicate with the docker daemon running in a `docker:dind` service. + +:::note +If your goal is to build/publish OCI images, consider using the [Docker Buildx Plugin](https://woodpecker-ci.org/plugins/Docker%20Buildx) instead. +::: + +First we need to define a service running a docker with the `dind` tag. +This service must run in `privileged` mode: + +```yaml +services: + - name: docker + image: docker:dind # use 'docker:-dind' or similar in production + privileged: true + ports: + - 2376 +``` + +Next, we need to set up TLS communication between the `dind` service and the step that wants to communicate with the docker daemon (unauthenticated TCP connections have been deprecated [as of docker v27](https://github.com/docker/cli/blob/v27.4.0/docs/deprecated.md#unauthenticated-tcp-connections) and will result in an error in v28). + +This can be achieved by letting the daemon generate TLS certificates and share them with the client through an agent volume mount (`/opt/woodpeckerci/dind-certs` in the example below). + +```diff +services: + - name: docker + image: docker:dind # use 'docker:-dind' or similar in production + privileged: true ++ environment: ++ DOCKER_TLS_CERTDIR: /dind-certs ++ volumes: ++ - /opt/woodpeckerci/dind-certs:/dind-certs + ports: + - 2376 +``` + +In the docker client step: + +1. Set the `DOCKER_*` environment variables shown below to configure the connection with the daemon. + These generic docker environment variables that are framework-agnostic (e.g. frameworks like [TestContainers](https://testcontainers.com/), [Spring Boot Docker Compose](https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-docker-compose) do all respect them). +2. Mount the volume to the location where the daemon has created the certificates (`/opt/woodpeckerci/dind-certs`) + +Test the connection with the docker client: + +```diff +steps: + - name: test + image: docker:cli # in production use something like 'docker:-cli' ++ environment: ++ DOCKER_HOST: "tcp://docker:2376" ++ DOCKER_CERT_PATH: "/dind-certs/client" ++ DOCKER_TLS_VERIFY: "1" ++ volumes: ++ - /opt/woodpeckerci/dind-certs:/dind-certs + commands: + - docker version +``` + +This step should output the server and client version information if everything has been set up correctly. + +Full example: + +```yaml +steps: + - name: test + image: docker:cli # use 'docker:-cli' or similar in production + environment: + DOCKER_HOST: 'tcp://docker:2376' + DOCKER_CERT_PATH: '/dind-certs/client' + DOCKER_TLS_VERIFY: '1' + volumes: + - /opt/woodpeckerci/dind-certs:/dind-certs + commands: + - docker version + +services: + - name: docker + image: docker:dind # use 'docker:-dind' or similar in production + privileged: true + environment: + DOCKER_TLS_CERTDIR: /dind-certs + volumes: + - /opt/woodpeckerci/dind-certs:/dind-certs + ports: + - 2376 +``` diff --git a/docs/versioned_docs/version-2.8/20-usage/90-advanced-usage.md b/docs/versioned_docs/version-2.8/20-usage/90-advanced-usage.md index 065386fdf..c44c2baeb 100644 --- a/docs/versioned_docs/version-2.8/20-usage/90-advanced-usage.md +++ b/docs/versioned_docs/version-2.8/20-usage/90-advanced-usage.md @@ -127,3 +127,93 @@ WOODPECKER_ENVIRONMENT=first_var:value1,second_var:value2 ``` Note that this tightly couples the server and app configurations (where the app is a completely separate application). But this is a good option for truly global variables which should apply to all steps in all pipelines for all apps. + +## Docker in docker (dind) setup + +:::warning +This set up will only work on trusted repositories and for security reasons should only be used in private environments. +See [project settings](./75-project-settings.md#trusted) to enable trusted mode. +::: + +The snippet below shows how a step can communicate with the docker daemon via a `docker:dind` service. + +:::note +If your aim ist to build/publish OCI images, consider using the [Docker Buildx Plugin](https://woodpecker-ci.org/plugins/Docker%20Buildx) instead. +::: + +First we need to define a servie running a docker with the `dind` tag. This service must run in privileged mode: + +```yaml +services: + - name: docker + image: docker:27.4-dind + privileged: true + ports: + - 2376 +``` + +Next we need to set up TLS communication between the `dind` service and the step that wants to communicate with the docker daemon (since Unauthenticated TCP connections have been deprecated [as of docker v26](https://github.com/docker/cli/blob/v27.4.0/docs/deprecated.md#unauthenticated-tcp-connections) and will ve removed in release v28). + +We can achieve this by letting the daemon generate TLS certificates for us and share them with the client via a volume mount in the agent (`/opt/woodpeckerci/dind-certs` in the example below). + +```diff +services: + - name: docker + image: docker:27.4-dind + privileged: true ++ environment: ++ DOCKER_TLS_CERTDIR: /dind-certs ++ volumes: ++ - /opt/woodpeckerci/dind-certs:/dind-certs + ports: + - 2376 +``` +In the step that needs access to the daemon we need to: + +1. Set the `DOCKER_*` environment variables shown below, setting up the connection with the daemon. These are standardized environment variables that should work with the docker client used by your framework of choice (e.g. [TestContainers](https://testcontainers.com/), [Spring Boot Docker Compose](https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-docker-compose) or similar). +2. Mount the volume where the daemon has created the certificates (`/opt/woodpeckerci/dind-certs`) + +In this example we test the connection with the vanilla docker client: + +```diff +steps: + - name: test + image: docker:27.4-cli ++ environment: ++ DOCKER_HOST: "tcp://docker:2376" ++ DOCKER_CERT_PATH: "/dind-certs/client"27.4-cli ++ DOCKER_TLS_VERIFY: "1" ++ volumes: ++ - /opt/woodpeckerci/dind-certs:/dind-certs + commands: + - docker version +``` + +This step should output version information of the client and the server if everything has been set correctly. + +Complete example: + +```yaml +steps: + - name: test + image: docker:27.4-cli + environment: + DOCKER_HOST: "tcp://docker:2376" + DOCKER_CERT_PATH: "/dind-certs/client"27.4-cli + DOCKER_TLS_VERIFY: "1" + volumes: + - /opt/woodpeckerci/dind-certs:/dind-certs + commands: + - docker version + +services: + - name: docker + image: docker:27.4-dind + privileged: true + environment: + DOCKER_TLS_CERTDIR: /dind-certs + volumes: + - /opt/woodpeckerci/dind-certs:/dind-certs + ports: + - 2376 +```