Migrating Jenkins Containers

Jenkins Installation Overview

Jenkins was installed on a docker host, provided with two docker volumes for data, a discrete network, exposed network ports, and a custom image. It can be started by running the following command:

sudo docker run --name jenkins-blueocean-jdk21 --restart=on-failure --detach --network jenkins --env DOCKER_HOST=tcp://docker:2376 --env DOCKER_CERT_PATH=/certs/client --env DOCKER_TLS_VERIFY=1 --publish 8080:8080 --publish 50000:50000 --dns 10.20.1.1 --volume jenkins-data:/var/jenkins_home --volume jenkins-docker-certs:/certs/client:ro myjenkins-blueocean:21-latest

Above command was created following the official Jenkins Guide here. That was great, until the docker host became severely corrupted, and I needed to migrate to a new host.

Jenkins Persistent Data

Persistent data on the Jenkins container is handled by two docker volumes:

  • jenkins-data
  • jenkins-docker-certs

Technically, these data volumes exist on the docker host through little obfuscation, and can be foound by running the docker volume [volume-name] inspect command:

[
    {
        "CreatedAt": "2025-05-03T00:58:23Z",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/jenkins-data/_data",
        "Name": "jenkins-data",
        "Options": null,
        "Scope": "local"
    }
]

Jenkins BlueOcean Image

Jenkins Docker installation guide listed earlier is all you need, but I recommend using the latest image instead of a blind copy-paste. Or at the very minimum, make sure the version you use is equal to the version you were on:

FROM jenkins/jenkins:latest-jdk21
USER root
RUN apt-get update && apt-get install -y lsb-release
RUN curl -fsSLo /usr/share/keyrings/docker-archive-keyring.asc \
  https://download.docker.com/linux/debian/gpg
RUN echo "deb [arch=$(dpkg --print-architecture) \
  signed-by=/usr/share/keyrings/docker-archive-keyring.asc] \
  https://download.docker.com/linux/debian \
  $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list
RUN apt-get update && apt-get install -y docker-ce-cli
USER jenkins
RUN jenkins-plugin-cli --plugins "blueocean docker-workflow"

Recreate this Docker file on the target host to help you rebuild your image:

sudo docker image build -t myjenkins-blueocean:21-latest .

Migration Plan

Step by step plan to migrate the Docker volumes from one host to another.

  1.  Backup Jenkins persistent data volumes
    1.  Create a temporary directory on the docker host: sudo mkdir /backup
    2. Creat tarball of data from jenkins-datasudo docker run --rm --mount type=bind,src=/backup,dst=/backup --volume jenkins-data:/jenk-backup busybox tar --create --verbose --file /backup/jenkins-data-backup.tar --numeric-owner /jenk-backup
    3. Creat tarball of data from jenkins-docker-certssudo docker run --rm --mount type=bind,src=/backup,dst=/backup --volume jenkins-docker-certs:/jenk-backup busybox tar --create --verbose --file /backup/jenkins-docker-certs-backup.tar --numeric-owner /jenk-backup
  2. Copy data backups from one docker host to another using scp
    1. Create a temporary directory on the docker host: sudo mkdir /backup
    2. Copy backups to temporary directory
    3. Recreate jenkins-data volume: sudo docker volume create jenkins-data
    4. Recreate jenkins-docker-certs volume: sudo docker volume create jenkins-docker-certs
  3. Restore tarball backups to the volumes
    1. Restore the tarball of data from the jenkins-datasudo docker run --rm --mount type=bind,src=/backup,dst=/backup --volume jenkins-data:/jenk-backup busybox tar xvf /backup/jenkins-data-backup.tar -C /
    2. Restore the tarball of data from the jenkins-docker-certssudo docker run --rm --mount type=bind,src=/backup,dst=/backup --volume jenkins-docker-certs:/jenk-backup busybox tar xvf /backup/jenkins-docker-certs-backup.tar -C /
    3. Create Docker image on target host: sudo docker image build -t myjenkins-blueocean:21-latest .
  4. Create the jenkins bridge network: sudo docker network create jenkins
  5. Start the jenkins host on the new node: sudo docker run --name jenkins-blueocean-jdk21 --restart=on-failure --detach --network jenkins --env DOCKER_HOST=tcp://docker:2376 --env DOCKER_CERT_PATH=/certs/client --env DOCKER_TLS_VERIFY=1 --publish 8080:8080 --publish 50000:50000 --dns 10.20.1.1 --volume jenkins-data:/var/jenkins_home --volume jenkins-docker-certs:/certs/client:ro myjenkins-blueocean:21-latest
  6. Update the Jenkins IP Address within System -> Jenkins Location -> Jenkins URL.

Lessons Learned

  1. The permissions for files on the data volumes matter. By default, tar will not preserve these during compression, or will replace them with the user executing the extract commands.
  2. Jenkins installation guide will have you version lock by default. This will hurt you when you go to deploy a new controller and you've accidentally downgraded yourself and your plugins fail.
  3. Jenkins will still function without the correct URL configured in System, but will be very slow until you do.
  4. Ensure any agents have their IP Addresses updated.