How to Fix ‘docker: not found’ in Jenkins Docker Container Pipelines

When utilizing Jenkins within a Docker container for Continuous Integration and Continuous Delivery (CI/CD) workflows, a frequent challenge arises during attempts to build Docker images.

Pipelines may abruptly halt with an error message similar to docker: not found. This indicates that the Jenkins environment, specifically the container it’s running in, cannot locate the Docker command-line interface (CLI).

Typically, this issue surfaces when Jenkins is started with the Docker socket mounted (e.g., -v /var/run/docker.sock:/var/run/docker.sock), intending to use the host’s Docker daemon, but without the necessary client tools inside the Jenkins container itself. This article explores the underlying reasons for this problem and presents several practical solutions to enable Docker operations within your containerized Jenkins pipelines.

Why This Error Occurs: The Missing Docker Client

The core of the problem is straightforward: the standard Jenkins Docker images (like jenkins/jenkins:lts) do not bundle the Docker CLI. While mounting the host’s Docker socket (/var/run/docker.sock) allows the Jenkins container to communicate with the Docker daemon running on the host machine, this communication requires a Docker client program.

If this client is not installed within the Jenkins container, any command starting with docker (e.g., docker build, docker ps) will fail because the executable cannot be found in the container’s PATH.

Effectively, two components are necessary:

  1. Access to a Docker Daemon: Usually achieved by volume-mounting the host’s Docker socket.
  2. Docker Client (CLI): Must be installed and accessible within the Jenkins container.

The docker: not found error signals that the second component is missing.

Read: How to Fix the Docker Error: ‘bind: address already in use’;

Strategies for Enabling Docker Commands in Jenkins

Several approaches can resolve this issue, ranging from installing the Docker client directly into a running container (less ideal for persistence) to building custom Jenkins images or using Jenkins’ built-in tool management.

How to enable Docker commands in Jenkins?

1. Installing the Docker Client within a Custom Jenkins Image

A robust and recommended method involves creating a custom Docker image based on an official Jenkins image, but with the Docker CLI tools added. This ensures the tools are always available when the container starts.

You can create a Dockerfile like the following:

Installing Docker CLI in Jenkins Image

Read: Setting Timezones in Docker Containers

Using code:


FROM jenkins/jenkins:lts-jdk11 # Always pin to a specific LTS version

USER root

# Install Docker CLI
# Method A: Using the official get.docker.com script
RUN curl -fsSL https://get.docker.com/get-docker.sh | sh

# Method B: Downloading specific binaries (example for a specific version)
# RUN curl -fsSLO https://download.docker.com/linux/static/stable/x86_64/docker-17.04.0-ce.tgz \
#   && tar xzvf docker-17.04.0-ce.tgz \
#   && mv docker/docker /usr/local/bin \
#   && rm -r docker docker-17.04.0-ce.tgz

# Add jenkins user to the docker group (created by the Docker installation script)
# This grants permission to use the Docker socket
RUN usermod -aG docker jenkins

USER jenkins
        

Read: How to Fix Docker Error: Executable File Not Found in $PATH

Build this Dockerfile (e.g., docker build -t my-custom-jenkins -f #YourDockerfileJenkinsName# .) and then run your Jenkins container using this new image. Remember to still mount the Docker socket:


docker run --name myjenkins -p 8080:8080 -p 50000:50000 \
  -v #your_jenkins_home_volume_or_path#:/var/jenkins_home \
  -v /var/run/docker.sock:/var/run/docker.sock \
  my-custom-jenkins
        

This approach ensures that the Docker client is correctly installed and the jenkins user has appropriate permissions.

Alternatively, a docker-compose.yml file can manage the build and deployment of this custom Jenkins service. For instance:

Jenkins Docker Integration

Using code: 


version: '3.8'
services:
  jenkins:
    build:
      context: .
      dockerfile: #YourDockerfileJenkinsName# # Points to your custom Dockerfile
    image: my-custom-jenkins # Optional: names the built image
    container_name: jenkins_service
    restart: always
    ports:
      - "8080:8080"
      - "50000:50000"
    volumes:
      - jenkins_data:/var/jenkins_home # Use a named volume for jenkins_home
      - /var/run/docker.sock:/var/run/docker.sock
    # Consider not running as root or privileged if usermod -aG docker jenkins is effective
    # user: root # if jenkins user needs root privileges temporarily during setup
    # privileged: true # Use with caution, only if absolutely necessary

volumes:
  jenkins_data:
        

Using USER root temporarily in the Dockerfile for installation and then switching back to USER jenkins is a common pattern. Adding the `jenkins` user to the `docker` group (which should own `docker.sock` or have access to it) is crucial for permission handling.

Read: How to Fix Docker Permission Denied Errors When Connecting to docker.sock

2. Leveraging Jenkins Global Tool Configuration

Jenkins can automatically download and install tools, including Docker, through its administrative interface. This method avoids building a custom Docker image but requires configuration within Jenkins itself.

  1. Navigate to “Manage Jenkins” → “Global Tool Configuration”.
  2. Scroll down to “Docker” (or “Docker Installations”) and click “Add Docker”.
  3. Provide a “Name” (e.g., docker-latest).
  4. Check the box for “Install automatically”.
  5. Click “Add installer” and choose “Download from docker.com”. Select a version or leave as “latest”.
  6. Save the configuration.

Then, in your Jenkinsfile, you must reference this tool and add its binaries to the PATH environment variable for your pipeline stages:


pipeline {
    agent any
    stages {
        stage('Initialize Docker') {
            steps {
                script {
                    // 'docker-latest' must match the name configured in Global Tool Configuration
                    def dockerHome = tool name: 'docker-latest', type: 'dockerTool'
                    env.PATH = "${dockerHome}/bin:${env.PATH}"
                }
            }
        }
        stage('Build Docker Image') {
            steps {
                sh 'docker --version'
                sh 'docker build -t my-app .'
                // other docker commands
            }
        }
    }
}
        

A potential follow-up issue here can be permissions to /var/run/docker.sock. If you encounter “Cannot connect to the Docker daemon” errors, ensure the Jenkins user (inside the container) has permissions. This often involves adding the jenkins user to the docker group (see solution 1’s Dockerfile or manually via docker exec if the group GID matches appropriately).

3. Mounting the Host’s Docker CLI (Use with Caution)

Another method involves directly mounting the host’s Docker client binary into the Jenkins container. This can be achieved by adding a volume mount to your docker run command:


docker run --name myjenkins -p 8080:8080 -p 50000:50000 \
  -v #your_jenkins_home_volume_or_path#:/var/jenkins_home \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v $(which docker):/usr/bin/docker \ # Mounts host docker CLI
  jenkins/jenkins:lts 
        

Or, in a docker-compose.yml file:


# ...
    volumes:
      - #your_jenkins_home_volume_or_path#:/var/jenkins_home
      - /var/run/docker.sock:/var/run/docker.sock
      - /usr/bin/docker:/usr/bin/docker # Assuming host docker is at /usr/bin/docker
                                         # or use a path resolved by $(which docker) if compose preprocesses it
# ...
        

Important Consideration: This technique of mounting the host’s Docker binary is generally discouraged. The Docker client might be dynamically linked against libraries on the host system that are not present or are incompatible within the Jenkins container’s environment. This can lead to unexpected errors or failures.

It is often more reliable to install a compatible Docker client directly within the Jenkins container or image.

4. Utilizing Pre-configured Jenkins Images with Docker

Some third-party Docker images come with Jenkins and Docker CLI pre-installed and configured. An example mentioned is getintodevops/jenkins-withdocker:lts.

Using such an image can simplify setup:


docker run --name myjenkins -p 8080:8080 -p 50000:50000 \
  -v #your_jenkins_home_volume_or_path#:/var/jenkins_home \
  -v /var/run/docker.sock:/var/run/docker.sock \
  getintodevops/jenkins-withdocker:lts
        

When opting for this, ensure the image is from a trusted source and is well-maintained.

Managing Docker Socket Permissions

Regardless of how the Docker CLI is made available, the Jenkins user inside the container must have permission to access the mounted Docker socket (/var/run/docker.sock). If the socket on the host is owned by root:docker with group-write permissions, common solutions include:

  • Adding Jenkins to Docker Group (in Image): As shown in Solution 1, use usermod -aG docker jenkins in your custom Dockerfile. This requires the docker group GID inside the container to match the GID of the docker.sock file on the host, or for the socket to be more permissively configured (less secure).
  • Using --group-add: When running the container, you can try adding the Jenkins user to the host’s docker group by GID.
    docker run --group-add $(getent group docker | cut -d: -f3) ...

    Or, if the group name docker is expected to map correctly:

    docker run --group-add docker ...

    This approach can fail if the docker group doesn’t exist on the host or cannot be found by the Docker daemon.

  • Running Jenkins Container as Root (Not Recommended): Setting user: root in docker-compose.yml or -u root in docker run will grant permissions but is a significant security risk.

The most secure and reliable permission setup usually involves ensuring the jenkins user inside the container is part of a group that has the same GID as the group owning the docker.sock on the host, and that this group has appropriate access rights to the socket.

Verification Steps

Once a solution is implemented, verify its effectiveness by running a simple Jenkins pipeline that executes a Docker command. For example:


pipeline {
    agent any
    stages {
        stage('Verify Docker Access') {
            steps {
                sh 'docker --version'
                sh 'docker ps -a'
            }
        }
    }
}
        

A successful execution of these commands in the Jenkins job console output, without the docker: not found error, confirms that the Docker CLI is accessible and functional.

Key Considerations Summary

Additionally, always ensure:

  • The Docker socket (/var/run/docker.sock) is correctly mounted into the Jenkins container.
  • The Jenkins user within the container has the necessary permissions to access the Docker socket.
  • Pin image versions (e.g., jenkins/jenkins:lts-jdk17) for consistency and to avoid unexpected changes from :latest tags.
  • Strive for the principle of least privilege, avoiding running containers as root or with --privileged unless absolutely necessary and fully understood.

Conclusion

The “docker: not found” error in a containerized Jenkins setup is a common hurdle, primarily stemming from the absence of the Docker CLI within the Jenkins container. By implementing one of the discussed solutions, such as building a custom Jenkins image with the Docker client, utilizing Jenkins’ Global Tool Configuration, or carefully considering other methods, and ensuring correct permissions for the Docker socket, it is possible to seamlessly integrate Docker build and management capabilities into Jenkins pipelines.

The most robust and maintainable approach typically involves creating a dedicated Jenkins image tailored to your CI/CD needs, including the necessary version of the Docker client.

 

 

Akil Sharma

Akil is a dedicated Cybersecurity Analyst with a strong focus on both offensive and defensive security techniques across Linux and Windows platforms. He delves into topics like vulnerability assessment, penetration testing methodologies, malware analysis, incident response, and implementing security frameworks. Akil is committed to educating readers on the latest threats and sharing actionable strategies for hardening systems and protecting data.