Skip to main content

Run Docker in GitLab Docker Executors

GitLab’s CI uses runners to “run” jobs. A runner is a service GitLab already provides, or you can host your own. Runners use executors, which determine the job’s environment. The most widely used is the Docker executor, where jobs run inside a Docker container.

Running Docker commands inside Docker containers is not a simple task. There are many ways to do it; my solution does not require changes to the GitLab runners.

job_that_uses_docker:
  before_script:
    # This is the part where you prepare the credentials if you need to push or pull from a private image registry.
    - docker login -u $DOCKER_LOGIN_USERNAME -p $DOCKER_LOGIN_PASSWORD $DOCKER_REGISTRY
  services:
    - name: docker:dind
      alias: docker
  # You can replace the image with anything that has the Docker CLI installed.
  image: docker:dind
  variables:
    DOCKER_HOST: tcp://docker:2375
    DOCKER_TLS_CERTDIR: ""
  script:
    # You can now call any Docker command here.
    - docker build <dockerfile-dir>
    - docker push <repo/image:tag>

This solution works by running the Docker Engine as a background service for the duration of the job. The variable DOCKER_HOST ensures that the job can connect to the service, which gets a DNS record from the service’s alias keyword. The variable DOCKER_TLS_CERTDIR is set to an empty string to bypass TLS certificate verification. It shouldn’t be an issue since the service is only used locally and is not listening to external connections.

The only disadvantage this has is that you cannot preserve any Docker resources (e.g., images, containers, volumes, networks) you’ll make during the job since the service will have ephemeral storage.