Why can't docker commit a Jenkins container with customized configuration? - jenkins

I pulled a Jenkins image and launched it. Then I did some configuration on that container. Now I want to save all my configuration into a new image. Below is the command I used:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f214096e4847 jenkins "/bin/tini -- /usr/lo" About an hour ago Up 1 seconds 50000/tcp, 0.0.0.0:8081->8080/tcp ci
From above output, you can see that the jenkins container f214096e4847 is running.
Now I use below command to commit my changes and create a new image:
$ docker commit f214096e4847 my_ci/1.0
sha256:d83801a700c4060326a5209b87281bfb0e93f46207d960038ba2d87628ddb90c
Then I stop the current container and run a new container from my_ci/1.0 image:
$ docker stop f214096e4847
f214096e4847
$ docker run -d --name myci -p 8081:8080 my_ci/1.0
aba1660be200291d499bf00d851a854c724193c0ee2afb3fd318c36320b7637e
But the new container doesn't include any changes I made. It looks like a container got created from original jenkins image. How to persist my data when using docker commit?
EDIT1
I know that I can add a volume to save the configuration data as below:
-v my_path:/var/jenkins_home
But I really want to save it on the docker image. So users don't need to provide the configuration from their host.

It's important to know that this isn't a good approach. As told you in the comments. The recommended way is to mount volumes.
But if you really want your volume in the image I can propose another way. You can create your own image derived from the official image:
Clone the git repo of the original image
git clone https://github.com/jenkinsci/docker.git
This contains the following:
CONTRIBUTING.md Jenkinsfile docker-compose.yml install-plugins.sh jenkins-volume plugins.sh update-official-library.sh
Dockerfile README.md init.groovy jenkins-support jenkins.sh tests weekly.sh
You just need to make one edit in the Dockerfile. Replace the VOLUME by a mkdir command
# Jenkins home directory is a volume, so configuration and build history
# can be persisted and survive image upgrades
#VOLUME /var/jenkins_home
RUN mkdir -p /var/jenkins_home
Rebuild your own image:
docker build -t my-jenkins:1.0
Start your own jenkins + install some plugins + create some jobs.
docker run -d -p 8080:8080 -p 50000:50000 my-jenkins:1.0
When you're ready with creating the desired jobs you can commit the container as an image.
docker commit 30c5889032a8 my-jenkins-for-developers:1.0
This newest jenkins container will contain your plugins + jobs by default.
docker run -d -p 8080:8080 -p 50000:50000 my-jenkins-for-developers:1.0
This will work in your case. But as I said. It's not recommended. It makes your content dependent of the image. So it's more difficult when you want to perform updates. Also your image can be too big (size).

Related

Exporting whole docker container for jenkins or just volume?

Create jenkins container and bind volume - jenkins-data
docker run --name myJenkins1 -p 8080:8080 -p 50000:50000 -v jenkins-data:/var/jenkins_home jenkins/jenkins:lts
make changes - update plugins, run builds etc
login to jenkins in browser etc
now export the whole container as a tar
docker export 2c8b996d3088 > jenkinsContainerAndVolume.tar
Since this includes the jenkins image, it seems quite large. I am going to need the jenkins image anyway, but wondered if there is a better practice or standard to save just the volume data?
The docker-export command doesn't save the container's volumes.
To backup the named volume you could use tar like this:
docker run -v jenkins-data:/dbdata -v $(pwd):/backup ubuntu tar zcvf /backup/backup.tar.gz /dbdata
In case you need to migrate this container with all its volumes to another host I use this script:
https://github.com/ricardobranco777/docker-volumes.sh

Docker update Jenkins container to image

I´m using a Docker Jenkins image, but I need to update the current version with some plugins. The idea is use the very same image in an environment where I dont have internet access so there´s no way I can add those plugins, so my idea was create a new image from the current container.
I read that is possible and I follow the steps:
Create new image
sudo docker commit CONTAINER_ID new_image_name
Run new image
sudo docker run --name cutom_image -p 8080:8080 -p 50000:50000 -e TERM=xterm -d new_image_name
But then when I connect by ssh to the container of the new updated image I cannot see any new installed plugin.
But when I see the size of the new image I can see that is a little bit bigger, so there´s must be some change.
Any idea what I´m doing wrong?
Regards.
The Jenkins/Jenkins docker image is normally run with:
docker run -p 8080:8080 -p 50000:50000 -v jenkins_home:/var/jenkins_home jenkins/jenkins:lts
this will automatically create a 'jenkins_home' volume on docker host, that will survive container stop/restart/deletion.
If you commit the container, you do not commit the volume content associated with it.
Run your new image with the same options as your old image, and you will get back the same content (including the plugins subfolder)

Using docker pull & run to build dockerfile

I'm learning how to use docker.
I want to deploy a microservice for swagger. I can do
docker pull schickling/swagger-ui
docker run -p 80:8080 -e API_URL=http://myapiurl/api.json swaggerapi/swagger-ui
To deploy it, I need a dockerfile i can run.
How do i generate the dockerfile in a way I can run it with docker build ?
The original question asks for a Dockerfile, perhaps for some CI/CD workflow, so this answer addresses that requirement:
Create a very simple Dockerfile beginning with
FROM schickling/swagger-ui
Then from that directory run
$ docker build -t mycontainername .
Which can then be run:
$ docker run -p 80:8080 -e API_URL=http://myapiurl/api.json mycontainername
Usually the docker pull pulls the Dockerfile. The Dockerfile for swagger is on the docker repo for it if you wanted to edit it or customize it.
(https://hub.docker.com/r/schickling/swagger-ui/~/dockerfile/)
That one should work with the build command. The build command builds the image, the run command turns the image into a container. The docker pull command should pull the image in. You don't need to run docker build for it as you should already have the image from the pull. You only need to do docker run.

Apply changes to docker container after 'exec' into it

I have successfully shelled into a RUNNING docker container using
docker exec -i -t 7be21f1544a5 bash
I have made some changes to some json files and wanted to apply these changes to reflect online.
I am a beginner and have tried to restart, mount in vain. What strings I have to replace when I mount using docker run?
Is there any online sample?
CONTAINER ID: 7be21f1544a5
IMAGE: gater/web
COMMAND: "/bin/sh -c 'nginx'"
CREATED: 4 weeks ago
STATUS: Up 44 minutes
PORTS: 443/tcp, 172.16.0.1:10010->80/tcp
NAMES: web
You can run either create a Dockefile and run:
docker build .
from the same directory where your Dockerfile is located.
or you can run:
docker run -i -t <docker-image> bash
or (if your container is already running)
docker exec -i -t <container-id> bash
once you are in the shell make all the changes you please. Then run:
docker commit <container-id> myimage:0.1
You will have a new docker image locally myimage:0.1. If you want to push to a docker repository (dockerhub or your private docker repo) you can run:
docker push myimage:0.1
There are 2 ways to do it :
Dockerfile approach
You need to know what changes you have made into Docker container after you have exec into it and also the Dockerfile of the image .
Lets say you installed additional rpm using yum install command after entering into the container (yum install perl-HTML-Format) and updated some file say /opt/test.json inside contianer (take a backup of this file in Docker host in some directory or in directory Dockerfile exist)
The above command/steps you can place in Dockerfile as
RUN yum install perl-HTML-Format
COPY /docker-host-dir/updated-test.json /opt/test.json
Once you update the Dockerfile, create the new image and push it to Docker repository
docker build -t test_image .
docker push test_image:latest
You can save the updated Dockerfile for future use.
Docker commit command approach
After you made the changes to container, use below commands to create a new image from container's changes and push it online
docker commit container-id test_image
docker push test_image
docker commit --help
Usage: docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
You don't want to do that. After you figured out what you needed you throw away the running container (git rm 7be21f1544a5), repeat the changes in the Dockerfile and build a new image to run.

Jenkins with docker

My problem is:
docker run -d -p 8080:8080 asd/jenkins # everything's ok
# made changes at jenkins
docker commit container_with_jenkins # comitted
docker run -d -p 8080:8080 image_from_container_with_changes
# => Error: create: No command specified
Am I missing something?
How do one work with docker's images and save changes within container?
When you commit an image it does not inherit the CMD from its parent image. So when you start a container based on the new image, you need to supply a run command.
docker run -d image_from_container_with_changes java -jar /var/lib/jenkins/jenkins.war
where the run command of course depends on your specific installation.
Jenkins stores it's configuration in a directory, e.g. /root/.jenkins. What I would recommend is to create a directory on the host and link this as a volume:
docker run -v {absolute_path_to_jenkins_dir}:/root/.jenkins -d asd/jenkins
If you start a new container in the same way, it will have the same jobs etc. In case you make changes that do go into this directory (I don't know by head where plugins or updates are installed) you still might want to make a new image. In that case, use the -run option when you commit your container to specify new configuration,
docker commit -run='{"Cmd": ["java", "-jar", "/var/lib/jenkins/jenkins.war"]}' abc1234d

Resources