Draven
Draven

Reputation: 1467

Docker build & run only in first vagrant up

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 .

Upvotes: 1

Views: 784

Answers (1)

lee-pai-long
lee-pai-long

Reputation: 2292

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

Upvotes: 1

Related Questions