Skip to content

Commit

Permalink
Allow to run as a devcontainer (#104)
Browse files Browse the repository at this point in the history
  • Loading branch information
felipecrs authored Mar 4, 2024
1 parent 3b77ad6 commit 9f657f8
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 27 deletions.
25 changes: 25 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"build": {
"context": "..",
"dockerfile": "../Dockerfile"
},
"overrideCommand": false,
"mounts": [
"source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind"
],
"runArgs": ["--network=host"],
"postCreateCommand": "pkgx install hadolint k3d helmfile werf kubectl",
"customizations": {
"vscode": {
"extensions": [
"timonwong.shellcheck",
"ms-azuretools.vscode-docker",
"exiasr.hadolint",
"foxundermoon.shell-format",
"esbenp.prettier-vscode",
"github.vscode-github-actions",
"ms-kubernetes-tools.vscode-kubernetes-tools"
]
}
}
}
6 changes: 1 addition & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,7 @@ jobs:
- name: Setup test dependencies
uses: pkgxdev/setup@v2
with:
+: >
k3d
helmfile
werf
kubectl
+: k3d helmfile werf kubectl

- name: Build
uses: docker/build-push-action@v5
Expand Down
4 changes: 3 additions & 1 deletion .vscode/extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
"ms-azuretools.vscode-docker",
"exiasr.hadolint",
"foxundermoon.shell-format",
"esbenp.prettier-vscode"
"esbenp.prettier-vscode",
"github.vscode-github-actions",
"ms-kubernetes-tools.vscode-kubernetes-tools"
]
}
6 changes: 2 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,13 @@ ENV LANGUAGE="en_US:en"
ENV LC_ALL="en_US.UTF-8"
ENV TZ="Etc/UTC"

ENV CI="true"

RUN --mount=type=bind,source=scripts/prepare_image.sh,target=/prepare_image.sh \
/prepare_image.sh

COPY --from=rootfs / /

# use non-root user with sudo when needed
USER "${NON_ROOT_USER}:${NON_ROOT_USER}"
USER "${NON_ROOT_USER}"

WORKDIR "${AGENT_WORKDIR}"

Expand All @@ -70,4 +68,4 @@ ENV S6_SERVICES_GRACETIME="15000"
ENV S6_KEEP_ENV="1"

ENTRYPOINT [ "/entrypoint.sh" ]
CMD [ "jenkins-agent" ]
CMD []
68 changes: 55 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,23 @@
[![CI](https://github.com/felipecrs/jenkins-agent-dind/workflows/ci/badge.svg?branch=master&event=push)](https://github.com/felipecrs/jenkins-agent-dind/actions?query=workflow%3Aci+branch%3Amaster+event%3Apush)
[![Docker Image Size](https://ghcr-badge.egpl.dev/felipecrs/jenkins-agent-dind/size)](https://github.com/felipecrs/jenkins-agent-dind/pkgs/container/jenkins-agent-dind)

A full fledged Docker in Docker image to act as a Jenkins Agent. Based on `ubuntu`, it is a mashup of [`jenkins/inbound-agent`](https://github.com/jenkinsci/docker-agent/blob/HEAD/README_inbound-agent.md) with [`docker:dind`](https://github.com/docker-library/docker).
A full-fledged Docker in Docker image to act as a Jenkins Agent or Devcontainer.

- Docker image: [`ghcr.io/felipecrs/jenkins-agent-dind`](https://github.com/felipecrs/jenkins-agent-dind/pkgs/container/jenkins-agent-dind)
- Image tags: [`ghcr.io/felipecrs/jenkins-agent-dind`](https://github.com/felipecrs/jenkins-agent-dind/pkgs/container/jenkins-agent-dind)

> [!IMPORTANT]
> This image used to be uploaded to Docker Hub as `felipecrs/jenkins-agent` but it no longer is. Please update to the new tag `ghcr.io/felipecrs/jenkins-agent-dind`.
## Features

- Based on **Ubuntu 22.04 Jammy Jellyfish**: a more common OS to run your builds.
- Several common packages installed: run your builds without hassle.
- Fully working Docker in Docker: run your `docker build` commands isolated from the host Docker daemon.
- Act just as a Jenkins Agent out-of-the-box: run ephemeral build containers by using the Docker Plugin or Kubernetes Plugin on Jenkins. Works as the official `inbound-agent`.
- Includes [`pkgx`](https://pkgx.sh), a convenient package manager that allows you to easily install the necessary tools for your project. For example, you can use `pkgx install node@18` to install Node.js version 18.
- Facilitates debugging by providing an opt-in SSH server for your builds. Read more about it [here](#accessing-the-container-through-ssh).
- **Based on Ubuntu 22.04 Jammy Jellyfish**: a more common distribution to run your workload on.
- Fully functional **Docker in Docker**: run `docker` commands isolated from the host Docker daemon.
- Also supports **Docker on Docker**: you can choose to share the host's Docker daemon to avoid the overhead of running a nested Docker daemon.
- Works as a Jenkins Agent out-of-the-box: run ephemeral build containers by using the Docker Plugin or Kubernetes Plugin on Jenkins. Works as the official [`jenkins/inbound-agent`](https://github.com/jenkinsci/docker-agent/blob/master/README_inbound-agent.md).
- Several common packages installed: run your generic workflow without needing to install additional packages.
- Bundles [**`pkgx`**](https://pkgx.sh), a convenient package manager that allows you to **easily and quickly install the necessary tools for your project**. Example: `pkgx install node@18 npm@10`.
- Facilitates debugging by providing an **opt-in SSH server** for your builds. Read more about it [here](#accessing-the-container-through-ssh).
- Can also be used as a [**devcontainer**](https://containers.dev/), ensuring **both your development environment and your CI/CD environment are the same**. Read more about it [here](#devcontainer).

## Usage

Expand All @@ -29,14 +31,16 @@ Spin this image in your terminal, if you want to play with it:
# -it: allows to interact with the container
# --rm: removes the container and its volumes after exiting
# --privileged: needed for running Docker in Docker
docker run -it --rm --privileged ghcr.io/felipecrs/jenkins-agent-dind bash
docker run -it --rm --privileged ghcr.io/felipecrs/jenkins-agent-dind
```

Alternatively, you can use the Docker on Docker mode:

```sh
# --volume: shares the host's Docker socket with the container
docker run -it --rm --volume=/var/run/docker.sock:/var/run/docker.sock ghcr.io/felipecrs/jenkins-agent-dind bash
# --network=host: allows to access ports from other containers running on the host
docker run -it --rm --volume=/var/run/docker.sock:/var/run/docker.sock --network=host \
ghcr.io/felipecrs/jenkins-agent-dind
```

### Agent template with the [Docker Plugin](https://plugins.jenkins.io/docker-plugin/) on Jenkins
Expand Down Expand Up @@ -100,6 +104,7 @@ This ensures file permissions are correct when running as a `Jenkinsfile` docker
To run in Docker in Docker mode:

```groovy
// Jenkinsfile
pipeline {
agent {
docker {
Expand All @@ -123,12 +128,13 @@ pipeline {
Alternatively, you can use the Docker on Docker mode:

```groovy
// Jenkinsfile
pipeline {
agent {
docker {
image 'ghcr.io/felipecrs/jenkins-agent-dind'
alwaysPull true
args '--volume=/var/run/docker.sock:/var/run/docker.sock --group-add=docker'
args '--volume=/var/run/docker.sock:/var/run/docker.sock --network=host --group-add=docker'
}
}
stages {
Expand Down Expand Up @@ -233,6 +239,7 @@ spec:
And here is an example of a Jenkinsfile:

```groovy
// Jenkinsfile
pipeline {
agent any
options {
Expand All @@ -251,11 +258,13 @@ pipeline {
It also works if you use a nested Docker agent:

```groovy
// Jenkinsfile
pipeline {
agent {
docker {
image 'felipecrs/fixdockergid:latest'
args '--volume=/ssh-command:/ssh-command --volume=/var/run/docker.sock:/var/run/docker.sock --group-add=docker'
image 'ghcr.io/felipecrs/jenkins-agent-dind'
alwaysPull true
args '--volume=/ssh-command:/ssh-command --volume=/var/run/docker.sock:/var/run/docker.sock --network=host --group-add=docker'
}
}
options {
Expand All @@ -279,6 +288,8 @@ pipeline {
<summary>Click here to show</summary>

```groovy
// Jenkinsfile
// Generate an "unique" port for SSHD
env.SSHD_PORT = new Random(env.BUILD_TAG.hashCode()).nextInt(23000 - 22000) + 22000
Expand All @@ -305,3 +316,34 @@ pipeline {
```

</details>

### Devcontainer

It is a good practice to run your development environment in a container, so you can have a consistent environment across your team.

It is even better if you can run the same container in your CI/CD pipeline, so you can be sure that your build will behave the same way as your development environment.

As a Docker in Docker devcontainer:

```jsonc
// .devcontainer/devcontainer.json
{
"image": "ghcr.io/felipecrs/jenkins-agent-dind",
"overrideCommand": false,
"privileged": true
}
```

As a Docker on Docker devcontainer:

```jsonc
// .devcontainer/devcontainer.json
{
"image": "ghcr.io/felipecrs/jenkins-agent-dind",
"overrideCommand": false,
"mounts": [
"source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind"
],
"runArgs": ["--network=host"]
}
```
22 changes: 18 additions & 4 deletions rootfs/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,30 @@

set -eu

# Handle when no CMD is provided
if [[ $# -eq 0 ]]; then
# If JENKINS_URL is preset, assume we are running as a Kubernetes Pod template agent
if [[ -n "${JENKINS_URL:-}" ]]; then
set -- jenkins-agent
# Otherwise, if attached to a terminal, start a shell
elif [[ -t 0 ]]; then
set -- bash
# Otherwise, just keep the container running
else
set -- sleep infinity
fi
fi

uid="$(id -u)"
if [[ "${uid}" -eq 0 ]]; then
# If running as root, simply execute s6-overlay
export USER="root"
cmd=(/init_as_root)
set -- /init_as_root "$@"
else
# Otherwise, fix uid and gid, run s6-overlay as root and then drop
# privileges back to the user
export USER="${NON_ROOT_USER}"
cmd=(fixdockergid /init_as_root s6-setuidgid "${NON_ROOT_USER}")
export USER="${NON_ROOT_USER?}"
set -- fixdockergid /init_as_root s6-setuidgid "${NON_ROOT_USER}" "$@"
fi

exec -- "${cmd[@]}" "$@"
exec -- "$@"

0 comments on commit 9f657f8

Please sign in to comment.