Restart Docker Container (Automatically) when Image changes in Portainer(?) - image

I have a java WAR file that is of an Image (Docker) and is being started inside a Tomcat (Docker) container. Since the coding changes, the WAR will change also. I would like to do the following:
Change the java code Update to Git
Have a WAR file created (from code just pushed to Git)
create a NEW IMAGE (Docker) that uses the NEW WAR file
stop all old containers (running old image)
re-start the containers (which will be using the new image)
I am also using Portainer. Is there some series of commands that I can execute / run so that Item #4 and Item #5 can be ran automatically (without requiring human intervention)? Is there some kind of way that this can be done at all?
TIA

docker-compose can be helpful for this. You can create a yml file for your application and use docker compose cli to spin up new containers as required. For example I have tomcat/mongo based application with following yml file:
version: '3'
services:
mongodb:
image: mongo
network_mode: host
tomcat:
build:
context: ./app
dockerfile: DockerfileTomcat
network_mode: host
depends_on:
- mongodb
With folder layout as:
├── docker-compose.yml
└── app
├── DockerfileTomcat
└── app.war
Where DockerfileTomcat takes care of copying the war file in tomcat container as:
FROM tomcat:8.5-jre8
RUN rm -rf /usr/local/tomcat/webapps/*
COPY app.war /usr/local/tomcat/webapps/app.war
In order to start your application you need to run following command in the directory containing docker-compose.yml:
docker-compose up --build
Just copy the new war file over app.war each time and run the command above. It will create the base image and launch the updated container.
If this isn't something you are looking for you can write a BASH script to automate the process. Let me know if you want me to post it here.

Related

Is there a way to automate the creation of Docker Image?

I needed to create a Docker image of a Springboot application and I achieved that by creating a Dockerfile and building it into an image. Then, I used "docker run" to bring up a container. This container is used for all the activities for which my application was written.
My problem, however, is that the JAR file that I have used needs constant changes and that requires me to rebuild the Docker image everytime. Furthermore, I need to take the contents of the earlier running Docker container and transfer it into a container created from the newly built image.
I know this whole process can be written as a Shell script and exected every time I have changes on my JAR file. But, is there any tool I can use to somehow automate it in a simple manner?
Here is my Dockerfile:
FROM java:8
WORKDIR /app
ADD ./SuperApi ./SuperApi
ADD ./config ./config
ADD ./Resources ./Resources
EXPOSE 8000
CMD java -jar SuperApi/SomeName.jar --spring.config.location=SuperApi/application.properties
If you have a JAR file that you need to copy into an otherwise static Docker image, you can use a bind mount to save needing to rebuild repeatedly. This allows for directories to be shared from the host into the container.
Say your project directory (the build location where the JAR file is located) on the host machine is /home/vishwas/projects/my_project, and you need to have the contents placed at /opt/my_project inside the container. When starting the container from the command line, use the -v flag:
docker run -v /home/vishwas/projects/my_project:/opt/my_project [...]
Changes made to files under /home/vishwas/projects/my_project locally will be visible immediately inside the container1, so no need to rebuild (and probably no need to restart) the container.
If using docker-compose, this can be expressed using a volumes stanza under the services listing for that container:
volumes:
- type: bind
source: /home/vishwas/projects/my_project
target: /opt/my_project
This works for development, but later on, it's likely you'll want to bundle the JAR file into the image instead of sharing from the host system (so it can be placed into production). When that time comes, just re-build the image and add a COPY directive to the Dockerfile:
COPY /home/vishwas/projects/my_project /opt/my_project
1: Worth noting that it will default to read/write, so the container will also be able to modify your project files. To mount as read-only, use: docker run -v /home/vishwas/projects/my_project:/opt/my_project:ro
You are looking for docker compose
You can build and start containers with a single command using compose.

Docker container with two jar files , run on demand not as entry point

In my use case I would like to have two jar files in the containers. In typical docker image, I see an entry point, which basically starts the jar file. In my case, I will not know which program to be started, till the time the container is getting used in the K8s services. In my example, I have a jar file that applies the DDLs and the second Jar file is my application. I want the k8s to deploy my DDL application first and upon completion it will deploy my spring boot application (from a different jar but from same container ) next. There by I cannot give an entry point for my container, rather I need to run the specific jar file using command and argument from my yaml file. In all the examples I have come across, I see an entry point being used to start my java process.
The difference here from the post referred here is- i want to have the container to have two jar files and when I load the container through k8s, I want to decide which program to run from command prompt. One option I am exploring is to have a parametrized shell script, so I can pass the jar name as parameter and the shell will run java -jar . I will update here once I find something
solution update
Add two jars in the docker file and have a shell script that uses parameter. Use the below sample to invoke the right jar file form the K8s yaml file
spec: containers:
- image: URL
imagePullPolicy: Always name: image-name
command: ["/bin/sh"]
args: ["-c", "/home/md/javaCommand.sh jarName.jar"]
ports: - containerPort: 8080
name: http
A docker image doesn't have to run a java jar when starting, it has to run something.
You can simply make this something a bash script that will make these decisions and start the jar you like
Try to add the per-requisites in the Init Containers while deploying it to kubernetes and in the regular container you can place your application, it will make DDLs container to be initialized first and then the following application container can be executed.

How to update the application running in the docker container? (for example, spring boot)

I'm trying to figure out the docker for the hundredth time. Now I create spring-boot simple application and create docker image for it:
FROM openjdk:8
EXPOSE 8080
ADD /build/libs/hello-docker-0.0.1-SNAPSHOT.jar hello-docker.jar
ENTRYPOINT ["java", "-jar", "hello-docker.jar"]
What did i do step by step:
1) Build my app(as a result, my hello-docker-0.0.1-SNAPSHOT.jar appeared in the build folder)
2) moved to the directory where the Docker file is located and executed the command: docker build -f Dockerfile -t springdocker .
3) Run this image as container: docker run -p 8080:8080 springdocker
As a result, my application started successfully.
But now I decided to change something in my application. I did it and tried to repeat all the steps. 1-> 2-> error
On 2 stepa new image was created and the old one was in the active state. It turns out that I need to stop the old one and start a new one.
it is not comfortable. I intuitively understand that this is not how it should work. I do not understand how to properly update the container. I constantly change my application and if I need to stop the container then create an image and then launch it - this is not a convenience but a complication. With the same success, I can stop the my application and launch a new one without a docker. I understand that I do not understand how this works, and I want someone to explain to me how to do it.
You can use docker-compose, this will save you a lot of time.
Just write a docker-compose.yml file in the same folder as Dockerfile:
version: '3.5'
services:
yourapplication:
build: . -> this is the location of your dockerfile
image: yourapplication_imagename
container_name: yourapplication_containername
ports:
- "8080:8080"
tty: true
And, to update the application you only have to run:
docker-compose build --no-cache yourapplication
docker-compose up -d
This will recreate the image and replace the container with your updated app.
Without docker-compose: you already have a good thread about this here
You should automate your build process. If the desired result of this process is a docker image, your automated build process should not stop after creating the .jar
Fortunately, there is a good tutorial for building a Docker image for running a Spring Boot application using different build tools (Maven, Gradle):
https://spring.io/guides/gs/spring-boot-docker/
In the end, you will be able to deploy your application to a docker image using just
./mvnw install dockerfile:build

How to setup a docker project (dcproj) for a dotnet core Web API app in VS2017

I'm using dotnetcore to develop applications and one thing I noticed when creating a aspnetcore (2.1) web api was the option to "Enable Docker" on the project. See below:
This was really great for allowing me to run my web application against my local docker for debugging! :-D I see that I have a new .dcproj file for the docker project, a docker file in my web api and a yml file in the docker project. Everything I needed to run in debug.
Now I'm creating a dotnetcore console application (again core 2.1 is the version I'm using). Unfortunately, I dont have an "Enable Docker Support" option for console apps and would like to run my console app in my local docker instance. Visual studio version I'm running is as follows:
I had a look for and can't seem to find the docker project as a project type template. So I resorted to copying over the docker project from my web app and modifying it to run my console app... needless to say I'm not able to get this running. I get the following error when I try to launch the docker compose:
Failed to launch debug adapter
My docker file is identical to the one from the web project (that works), other than my project and dll names (these are set correctly).
My yml file is the same also, other than the names being changed also. Not sure what I'm doing wrong - has anyone managed to achieve this? I ultimately want to debug my console application when it's running in docker through Visual Studio debug.
Thanks for any pointers in advance!!
For verbosity, here's my Dockerfile:
FROM microsoft/dotnet:2.1.2-runtime-alpine3.7 AS base
WORKDIR /app
EXPOSE 52649
EXPOSE 44331
FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /src
COPY AI.EmitterJob.csproj AI.EmitterJob/
RUN dotnet restore AI.EmitterJob/AI.EmitterJob.csproj
COPY . .
WORKDIR /src/AI.EmitterJob
RUN dotnet build AI.EmitterJob.csproj -c Release -o /app
FROM build AS publish
RUN dotnet publish AI.EmitterJob.csproj -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "AI.EmitterJob.dll"]
And docker-compose.yml file:
version: '3.4'
services:
ai.emitterjob:
image: ${DOCKER_REGISTRY}ai_emitter
build:
context: .
dockerfile: ../AI.EmitterJob/Dockerfile
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=https://+:443;http://+:80
- ASPNETCORE_HTTPS_PORT=44331
ports:
- "52649:80"
- "44331:443"
volumes:
- ${APPDATA}/ASP.NET/Https:/root/.aspnet/https:ro
- ${APPDATA}/Microsoft/UserSecrets:/root/.microsoft/usersecrets:ro
Note - I know I dont need to expose ports or use volumes here (or set env vars) for the console app, but I wanted to keep changes from the web docker file that works, to a minimum.
Just in case anyone else wants to try this, I finally got it working!
When I copied over the docker file, the only line I changed was from this:
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
To this:
FROM microsoft/dotnet:2.1.2-runtime-alpine3.7 AS base
Because I'd used that alpine build before as a base image. Reverting back to the aspnetcore base image made this work fine.
Obviously, this isn't ideal for proper deployments and I need to find a sufficient replacement for the aspnetcore base image that will have the dotnetcore runtime installed.
I'm happy I can debug my console app through docker now! :-D

docker-compose up with volumes "no such file or directory"

I'm a beginner in working with docker especially docker compose. Currently, creation my initial easy docker environment, I run into the first error and I've no clue why.
I tried to search for a solution in stackoverflow but found nothing that could help me.
Starting my docker with "docker-compose up" I get the following error:
$ docker-compose up
Removing errorinstance_app_1
Recreating 8a358dfcb306_8a358dfcb306_8a358dfcb306_errorinstance_app_1 ...
Recreating 8a358dfcb306_8a358dfcb306_8a358dfcb306_errorinstance_app_1 ... error
ERROR: for 8a358dfcb306_8a358dfcb306_8a358dfcb306_errorinstance_app_1 Cannot start service app: oci runtime error: container_linux.go:265: starting container process caused "exec: \"./run.sh\": stat ./run.sh: no such file or directory"
ERROR: for app Cannot start service app: oci runtime error: container_linux.go:265: starting container process caused "exec: \"./run.sh\": stat ./run.sh: no such file or directory"
ERROR: Encountered errors while bringing up the project.
So. Following my folder structure:
Project
docker-compose.yml
Docker
Java
Dockerfile
src
run.sh
Following my docker-compose.yml:
version: '2'
services:
app:
build:
dockerfile: ./Docker/Java/Dockerfile
context: .
volumes:
- ./src:/usr/local/etc/
working_dir: /usr/local/etc/
command: ./run.sh
And following my docker file:
FROM java:7-jdk-alpine
# WORKDIR /usr/local/etc
run.sh
echo "Hello world."
Yes, I know that I could do that solution only in a docker-compose file. But in the future I need to extend the Dockerfile.
Can someone help me respectively does anyone see the issue?
The problem is with the base docker image you are using in dockerfile:
FROM java:7-jdk-alpine
You are trying to start container by running run.sh bash script. But the above image doesn't support bash itself
For reference, you can see the documentation of above image in docker hub page here. Quoting the necessary portion here:
java:alpine
...
To minimize image size, it's uncommon for additional related tools
(such as git or bash) to be included in Alpine-based images. Using
this image as a base, add the things you need in your own Dockerfile
(see the alpine image description for examples of how to install
packages if you are unfamiliar).
That's about the problem.
Now, I can think of 2 solutions:
Just use java:7-jdk as base image instead of java:7-jdk-alpine
Install bash on top of the base image java:7-jdk-alpine by changing dockerfile to:
FROM java:7-jdk-alpine
RUN apk update && apk upgrade && apk add bash
#WORKDIR /usr/local/etc
*source of steps to install bash in alpine linux is here
It looks like docker compose can't find your run.sh file. This file needs to be included in your docker image.
Change your Dockerfile to the following, then rebuild the image with docker build -t <YOUR_IMAGE_NAME> ..
FROM java:7-jdk-alpine
ADD run.sh /usr/local/etc/run.sh
Once your image is rebuilt, run docker-compose up again.
The easiest way to tackle the problem is to execute a bash session in the container, then inside the container, you have to check if the file exists in the
indicated path if the file is not in the path, it must be included when you create the image into the docker file or through a volume inside de docker-compose.
Another thing to check is the relative path you are using. It will be clear when you check the existence of the file inside de docker container
docker exec -it CONTAINER_NAME bash
I recommend you to create a volume in the docker compose file, as it is the easier way, and also the best way.
there is a question that I want to do you, why are you putting the Dockerfile file inside a Java path?
It is not a good idea o guideline to follow
The correct way is to put your dockerfile file into an environment folder, in such a way the dockerfile file is not related to the java source of your application
I got this Error quite a lot and after a lot of investigation, it looked like some images were corrupted.
Deleting those and rebuilding solve the problem. It was not docker installation or configuration itself.

Resources