This is how you get Drone to build your Docker images using a dedicated Docker runner, not just some generic container.
Let’s spin up a quick example. Imagine you have a simple Node.js app and you want Drone to build its Docker image.
Here’s a Dockerfile for that app:
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["node", "dist/index.js"]
And here’s a minimal .drone.yml to build and push this image to Docker Hub:
kind: pipeline
type: docker
name: default
steps:
- name: build_and_push
image: plugins/docker
settings:
repo: your-dockerhub-username/my-node-app
tags:
- latest
- ${DRONE_COMMIT_SHA}
dockerfile: Dockerfile
auto_tag: false
This pipeline definition is straightforward: it uses the plugins/docker image, tells it which repository to push to (your-dockerhub-username/my-node-app), and applies two tags: latest and the Git commit SHA. auto_tag: false means we’re explicitly defining our tags.
Now, the magic happens with the Drone server configuration. You need to tell Drone how to execute this pipeline. For a Docker runner, this means configuring Drone to use a Docker daemon.
On your Drone server, in the drone.yml configuration file (often /etc/drone/drone.yml or similar), you’ll have a runner section. For a Docker runner, it looks like this:
kind: secret
name: drone
# ... other drone settings ...
runner:
docker:
host: unix:///var/run/docker.sock
mount:
- /var/run/docker.sock:/var/run/docker.sock
This tells Drone to use its built-in Docker runner and to connect to the Docker daemon via the Unix socket at /var/run/docker.sock. The mount directive is crucial: it makes the host’s Docker socket available inside the Drone worker container, allowing the worker to control the host’s Docker daemon. This is how the plugins/docker step can actually build and push images.
When a commit is pushed to your repository, Drone receives the webhook. It then schedules the pipeline. The type: docker in your .drone.yml tells Drone to use a runner capable of Docker builds. If you have a Docker runner configured, it picks that up. The plugins/docker step is essentially a container that Drone runs on this Docker runner. This container then uses the mounted Docker socket to:
- Pull the base image (
node:18-alpine). - Copy your application files into the image.
- Run
npm installandnpm run buildcommands within temporary containers managed by the Docker daemon. - Create the final Docker image.
- Push the tagged images to your specified registry (Docker Hub in this case).
The DRONE_COMMIT_SHA is an environment variable automatically provided by Drone, giving you a unique tag for each build.
The key here is that Drone itself doesn’t build the Docker image. It orchestrates the process. It tells the Docker daemon (via the mounted socket) to build the image. This separation is powerful because your Drone server can be relatively lightweight, while the actual image building happens on a machine with a Docker daemon, which can be scaled independently.
The plugins/docker image is a pre-built container that knows how to interact with the Docker daemon’s API to perform build operations. It takes your Dockerfile, build context, and desired tags, and then issues the necessary commands to the daemon.
One subtle point is how the build context is handled. When you specify Dockerfile in your .drone.yml, the plugins/docker image assumes the Dockerfile is in the root of your repository. The entire repository is then sent as the build context to the Docker daemon. This means anything in your repo (except what’s in .dockerignore) can be COPYed into the image. If you had a complex build setup, you might need to adjust your Dockerfile or .dockerignore to keep the context small.
If you want to use a different Docker daemon (e.g., one running on a remote server or a different Docker Swarm/Kubernetes setup), you’d adjust the host and potentially the mount directives in your Drone server’s runner.docker configuration. For instance, if your Docker daemon is accessible via TCP on port 2375, you might see host: tcp://your-docker-host:2375.
The next thing you’ll likely want to do is secure your Docker registry credentials so they aren’t hardcoded or exposed in your .drone.yml.