Drone CI can be surprisingly complex to migrate to, especially when you’re coming from a deeply entrenched Jenkins setup.

Here’s a look at how a typical Jenkins pipeline, say for a Go application, might be migrated to Drone:

Jenkins Pipeline (Jenkinsfile):

pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                sh 'go build -v'
            }
        }
        stage('Test') {
            steps {
                sh 'go test -v ./...'
            }
        }
        stage('Deploy') {
            when {
                branch 'main'
            }
            steps {
                sh './scripts/deploy.sh'
            }
        }
    }
}

Drone CI Configuration (.drone.yml):

kind: pipeline
type: docker
name: default

steps:
  - name: build
    image: golang:1.20
    commands:
      - go build -v

  - name: test
    image: golang:1.20
    commands:
      - go test -v ./...

  - name: deploy
    image: plugins/drone-git
    settings:
      repo: <your-github-org>/<your-repo>
      branch: main

      token: {{ .Secrets.github_token }}

    commands:
      - ./scripts/deploy.sh
    when:
      branch:
        include:
          - main

The most surprising thing about Drone CI is how it leverages Docker for everything. Your build environment is a Docker container. This isn’t just about running commands inside a container; it’s the fundamental unit of execution, from fetching code to running your tests and deploying.

Let’s see this in action. Imagine you have a simple Node.js app.

Jenkinsfile:

pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                sh 'npm ci'
                sh 'npm run build'
            }
        }
        stage('Test') {
            steps {
                sh 'npm test'
            }
        }
    }
}

Drone CI (.drone.yml):

kind: pipeline
type: docker
name: default

steps:
  - name: install_dependencies
    image: node:18
    commands:
      - npm ci

  - name: build
    image: node:18
    commands:
      - npm run build

  - name: test
    image: node:18
    commands:
      - npm test

Notice how each stage in Jenkins often maps to a step in Drone. The image field in Drone specifies the Docker image to use for that step. This means you don’t need to pre-install Go or Node.js on your Jenkins agents; Drone pulls the specified image on demand. The commands section then executes your build, test, or deploy scripts within that container.

The core problem Drone CI solves is the "it works on my machine" syndrome, amplified for CI/CD. By making Docker the universal build environment, Drone ensures that your pipelines run in a consistent, reproducible, and isolated manner, regardless of the underlying host system. This drastically reduces the "it works on my machine" problem and the associated debugging headaches common in Jenkins, where agent configurations can drift.

You control Drone’s behavior through its declarative YAML configuration. Key elements include:

  • kind: pipeline: Identifies this as a Drone pipeline.
  • type: docker: Specifies that this pipeline will run using Docker. Other types exist (e.g., kubernetes).
  • name: A human-readable name for the pipeline.
  • steps: A list of sequential execution units.
  • name (within steps): A name for the individual step.
  • image: The Docker image to use for this step (e.g., golang:1.20, node:18, python:3.9).
  • commands: A list of shell commands to execute within the container.
  • environment: A map of environment variables to set for the step.
  • volumes: For mounting host or named volumes into the container, useful for caching or persistent data.
  • services: To run dependent services (like databases) alongside your build container.
  • when: Conditional execution based on branch, tags, commit message, etc.

The most common pitfall when migrating from Jenkins is the assumption that Drone has a direct equivalent for every Jenkins plugin. While Drone has a rich ecosystem of plugins (often for deployment or notification), for core build logic, you’re expected to define it within the commands of your steps, usually by invoking your language’s build tools or scripts. This means that a complex Jenkins pipeline relying on many custom Groovy scripts or specific plugins might require a significant rewrite of those functionalities into shell scripts or custom Docker images that Drone can then execute.

The next concept you’ll likely encounter is managing secrets and configuration across pipelines.

Want structured learning?

Take the full Drone course →