1

Question: Is there a way I can build and run a docker image only when first creating the vagrant machine?

Problem: When running vagrant provision I get an error saying docker: Error response from daemon: Conflict. The container name "/jenkins" is already in use by container <snip>.

Additional Info: I ran vagrant provision because I added another plugin to the plugins.txt file to automatically install when setting up the jenkins machine.

I created the build scripts in this way to make the vagrant machine build to be as fast as possible, and the docker image as small as possible (still needs work here). Also because I wanted to remove the Jenkins setup GUI, and created a default admin account.

Vagrantfile:

Vagrant.require_version ">= 1.5"

Vagrant.configure("2") do |config|

    config.vbguest.auto_update = false

    config.vm.provider :virtualbox do |v|
        v.customize [
            "modifyvm", :id,
            "--memory", 1024,
            "--natdnshostresolver1", "on",
            "--cpus", 2,
        ]
    end

    config.vm.box = "ubuntu/trusty64"
    config.vm.hostname = "dev-jenkins-site"

    # Forward jenkins port.
    config.vm.network "forwarded_port", guest: 8080, host: 8080

    config.vm.network :private_network, ip: "192.168.34.56"

    jenkins_dir = "/var/jenkins_home"

    # Run Dockerfile.
    config.vm.provision "docker"

    # Restart jenkins container, in case it was stopped (which is possible from a 'vagrant halt').
    #   This won't run if this after the docker build & run provision (below) when using 'vagrant provision' because it
    #   returns an error and exits before this can run.
    config.vm.provision "shell",
      inline: "docker restart jenkins",
      run: "always"

    # Only need to build the image and container one time.
    #   Using '--restart always' doesn't work when the container is stopped from 'vagrant halt'.
    config.vm.provision "shell",
      inline: "cd /vagrant && make jenkins && docker run -d --name jenkins -p 80:8080 -p 50000:50000 -v #{jenkins_dir}:#{jenkins_dir} draven/jenkins",
      run: "once"

    # Files on your local machine
    config.vm.synced_folder "./jenkins_home", jenkins_dir
    config.vm.synced_folder ".", "/vagrant"
end

Dockerfile:

FROM jenkins/jenkins:latest

COPY plugins.txt /usr/share/jenkins/ref/plugins.txt
RUN /usr/local/bin/install-plugins.sh < /usr/share/jenkins/ref/plugins.txt

ENV JENKINS_USER admin
ENV JENKINS_PASS admin

# Skip initial setup
ENV JAVA_OPTS -Djenkins.install.runSetupWizard=false

COPY default-user.groovy /usr/share/jenkins/ref/init.groovy.d/

VOLUME /var/jenkins_home

Makefile:

SHELL:=/bin/bash

jenkins:
    cd docker-image && docker build -t draven/jenkins .
Draven
  • 1,467
  • 2
  • 19
  • 47

1 Answers1

1

Vagrant provision always run all provisioners if not instructed otherwise.

A solution is to make your docker provisioner idempotent by first deleting a container of the same name if exist:

config.vm.provision "shell",
  run: "once",
  inline: <<-SHELL
    cd /vagrant \
    && docker ps -a -f "name=jenkins" \
    && docker rm jenkins;
    make jenkins \
    && docker run -d \
        --name jenkins \
        -p 80:8080 -p 50000:50000 \
        -v #{jenkins_dir}:#{jenkins_dir} \                   
        draven/jenkins
  SHELL
lee-pai-long
  • 2,147
  • 17
  • 18
  • This should work for me since my `jenkins_home/` folder doesn't get deleted. Is `docker ps -a -f "name=jenkins"` necessary though? If so, why? And can it not display the contents in the console? – Draven Aug 21 '17 at 21:59
  • -a is for all not just the running containers, and -f is to filter directly with docker but you can also do a `| grep jenkins`. If you don't need the output you can redirect stdout (and or stderr) to /dev/null (check this [answer](https://stackoverflow.com/a/876267/3775614)). – lee-pai-long Aug 22 '17 at 08:04
  • Sorry, I think my question was unclear. Is `docker ps -a -f "name=jenkins"` necessary to stop the container with `docker rm jenkins`? Seems to me that I can just use `docker rm jenkins` all by itself since it does not depend on `docker ps` output. – Draven Aug 22 '17 at 14:30
  • Well with ` docker ps -a -f "name=jenkins" && docker rm jenkins` you are tying to delete the *jenkins* container only if the previous command succeed(so only if a container with that name exist) otherwise the `docker rm` could return false(1) when no container named *jenkins* exist. But you can also just redirect the result of the `docker rm` to */dev/null* and always run the next command. Personally I prefer the first approach that's all. – lee-pai-long Aug 22 '17 at 15:06