Docker for devs with hands-on| Part-4
In case you are landing here directly, it’s recommended to read through this documentation first.
Following are the topics, which we shall be touching through this blog :-
- Introduction to Dockerfile.
- Generation of DockerImage from Dockerfile.
- Launching Docker container from DockerImage.
- Pre-defining instructions from Dockerfile.
- Copying files from local to Container.
- Executing simple-service in container using Dockerfile.
- Difference between ADD & COPY operations.
- Launching simple tomcat within Docker-container.
- Deploying full fledged WAR file (Spring based WebApp) inside the Docker container containing tomcat based docker image.
- Deploying full fledged JAR file (Spring Boot based App) inside the Docker container containing JDK based docker image.
Question :- Alright, we now created an enhanced Docker-Image of our own. But, wait wait… Is it a good idea always to create and store images like this ?
Answer:- The reason why it’s not a good idea generally is that the image that we’ve just created is not repeatable. And I have no way of looking at that image in four years time and getting any kind of understanding as to what’s inside that image. I could have put anything in there. So, for that reason, we almost always would create images using a Docker file instead.
Question :- Let’s demonstrate the process of launching Docker Container from the simple DockerFile ?
Step #1.) Let’s see the DockerFile (containing simple commands) :-
FROM ubuntu:latest
MAINTAINER Aditya Goel "adityagoel123@gmail.com"
RUN apt-get update && apt-get install -y openjdk-8-jdk
CMD ["/bin/bash"]
We have the DockerFile being placed in one of the directory :-
Step #2.) Let’s now build a image from this Dockerfile :-
docker image build -t image-from-docker-file .
Step #3.) Let’s now verify that, whether the images has been formed new :-
docker images
Step #4.) Let’s now confirm that, we don’t have any container active right now :-
docker container ps
Step #5.) Let’s now launch a fresh container(In Interactive mode) from the new image that we have recently created from the DockerFile:-
docker container run -ti image-from-docker-file
Step #6.) Let’s now exit from the aforesaid container and see it in list of our containers :-
docker container ps -a
Question :- Now, we want to further launch a fresh container from Dockerfile and also transfer some java based JAR file to the container ?
Step #1.) Let’s see the DockerFile (containing simple commands) :-
FROM ubuntu:latest
MAINTAINER Aditya Goel "adityagoel123@gmmail.com"
RUN apt-get update && apt-get install -y openjdk-8-jdk
COPY simple-java.jar /usr/local/bin/
CMD ["/bin/bash"]
Note here that, CMD is command that we wish to execute, once we start this container. Also, we can also re-write the aforesaid Dockerfile as below :-
FROM ubuntu:latest
MAINTAINER Aditya Goel "adityagoel123@gmmail.com"
RUN apt-get update && apt-get install -y openjdk-8-jdk
WORKDIR /usr/local/bin/
COPY simple-java.jar .
CMD ["/bin/bash"]
Note here that, we have defined the current-working-directory as the particular directory and then copied the JAR file from our local machine to the CWD. Also, we have now placed the DockerFile below directory :-
Step #2.) Let’s first see, from which java class file, have we generated the JAR :-
We now try to run the above java based JAR file at our local machine :
java -jar <NAME_OF_JAR.jar>
Step #3.) Let’s now generate a fresh Docker Image from this Dockerfile :
docker image build -t image-from-docker-file .
Step #4.) Let’s verify whether a fresh Docker-Image got generated from aforementioned step:
docker images
Step #5.) Let’s launch a fresh container from newly generated DockerImage:
docker container run -it <NAME_OF_DOCKER_IMAGE>
Please note below crucial points :-
- We had ran the container with “-i” option which means interactive mode.
- We had ran the container with “-t” option which means, we shall connect to the container’s terminal as well.
- In the fresh container that we just launched, observe that JDK is already installed, as suggested in the Dockerfile itself.
- In the fresh container , also observe that a JAR file has also been copied, because the same has been mentioned in the Dockerfile.
Step #6.) Let’s now exit from our container and observe whether this container really shows up in the list anymore :-
docker container ls -a
Step #7.) Let’s now re-start our container again :-
docker container start <container_id>
Step #8.) Let’s now connect to our afore-started container. We shall log inside a bash shell inside this freshly launched container again :-
docker container exec -it <container_id> bash
Step #9.) Let’s now manually run the JAR file :-
java -jar <NAME_OFJAR_FILE.jar>
Question :- Can we also specify that particular Java based command to execute inside container, from the Dockerfile itself ?
Step #1.) Let’s see the DockerFile (containing simple commands) :-
FROM ubuntu:latest
MAINTAINER Aditya Goel "adityagoel123@gmmail.com"
RUN apt-get update && apt-get install -y openjdk-8-jdk
WORKDIR /usr/local/bin/
COPY simple-java.jar .
CMD ["java", "-jar", "simple-java.jar"]
Step #2.) Let’s list down active containers that we have :-
docker container ls
We note that, we have ONE active container here :-
Step #3.) Let’s now stop this container first :-
docker container stop <CONTAINER_ID>
Step #4.) Let’s now list down all containers we have :-
docker container ls -a
Step #5.) Let’s now kill all of these stopped / inactive containers :-
docker stop <Container-IDs>
Note that, we can just mention the first 2 chars of the container-id as well.
Step #6.) Let’s now again verify, whether the 3 containers are now gone :-
docker container ls -a
Step 7.) Let’s now generate a fresh Docker Image from this Dockerfile and verify, whether new image got generated :
docker image build -t image-from-docker-file .docker images
Step #8.) Let’s launch a fresh container from newly generated DockerImage:
docker container run -it <NAME_OF_DOCKER_IMAGE>
The big difference this time is, we’re not dropped into the back shell, it’s actually immediately doing something useful, of course, this could be a Web server as Spring Boots application. This is because, we have instructed in Dockerfile itself that, execute the Jar file.
Step #9.) Let’s exit out from our container and see it in our list :-
docker container ps -a
Step #10.) Let’s start our container fresh and observe the logs of our container :-
docker container start <CONTAINER-ID>docker container logs <CONTAINER-ID>
Note that, as soon as we start the container above, it gets started in DETACHED mode (See that, container status is Up) :-
Question:- What’s the difference between COPY and ADD commands in Dockerfile ?
Answer:- It’s quite difficult to see if you compare the two, they look very, very similar and they are. It’s just that the ADD command has some extra features. For example :-
- ADD command can work with remote-urls.
- It can also do things like unzipping or unpacking archives.
- It looks like ADD is generally more useful and flexible.
- COPY command is preferred because it’s just simpler and is more obvious what copy is going to do.
Question:- What’s the difference between CMD and ENTRYPOINT commands in Dockerfile ?
Answer:-
- If you’re working with an image that has CMD, if you wish, you can change the command that gets executed. So, I could instead of running that Java service, I could just get dropped inside the bash terminal of Docker container. And that’s going to start the container from the image, but it overrides that default command. And as you can see, I’m now dropped onto the command line and I could start doing diagnostics or whatever I want to do.
- The same isn’t true of entry points. Now, this is a hard coded command, we rerun the build and then run a container from it and notice
FROM ubuntu:latest
MAINTAINER Aditya Goel "adityagoel123@gmmail.com"
RUN apt-get update && apt-get install -y openjdk-8-jdk
WORKDIR /usr/local/bin/
ADD simple-java.jar .
ENTRYPOINT ["java", "-jar", "simple-java.jar"]
Question:- Now, I want “tomcat” inside our container. What are the ways ?
Answer:-
Part #1.) One of the ways of achieving this is that :
- First, we install JAVA/JDK inside our ‘ubuntu’ docker-container.
- Next, we install tomcat inside our ‘ubuntu’ docker-container.
Or the other way is to use the readily available docker-image, which contains the tomcat, pre-installed in it.
Part #2.) Next, let’s search for some official ready-made tomcat based Docker-Image :-
Note that, we have got many tags available for this particular docker-image.
Part #2.) We would be choosing the “8.5.73-jdk8-openjdk” tag of this “tomcat” image and download it first.
docker image pull tomcat:8.5.73-jdk8-openjdk
Part #3.) Let’s see, if this image has been downloaded well onto our local machine.
docker images
Part #4.) Let’s start the corresponding container from this image
docker container run -p 8081:8080 -ti tomcat:8.5.73-jdk8-openjdk
Part #4.) Let’s do this require step as well, to see the tomcat in container. So, first we login to the container recently launched and copy the webapps directory :-
docker container exec -it da31ab329d77 bash
Part #5.) Let’s now verify by opening the web-page exposed by this docker container :-
Part #6.) Lets now stop this container & remove it :-
docker container stop <container_id>
docker container rm <container_id>
Lets now verify which all containers do we have ?
docker ps -a
Note that, the containers have been stopped as well as removed now.
Part #7.) Let’s now see, which all images we have. Note that, we have “tomcat” based image present with us, because we downloaded it in above sections.
docker images
The highlighted one, we shall be removing going forward.
Part #7.) Let’s now remove corresponding images :-
docker image rm <Image_ID>
Part #7.) Let’s again visualise, which all images do we have with us now :-
docker images
Observe that, now we don’t have any image for “tomcat” related now.
Question:- Kindly demonstrate the launch-process of simple tomcat based Docker container with the help of Dockerfile :-
Answer:-
Part #1.) Note that, we can also write a Dockerfile for all of the above operations (i.e. launching container containing tomcat) too :-
FROM tomcat:8.5.73-jdk8-openjdk
MAINTAINER Aditya Goel "adityagoel123@gmail.com"
CMD ["catalina.sh", "run"]
RUN mv /usr/local/tomcat/webapps.dist/* /usr/local/tomcat/webapps/
Note that, with RUN mv command, we are copying a particular directory from one folder to another folder 📂 , within the container itself.
Part #2.) Let’s now head to our best friend terminal and change directory to the place, where we have our Dockerfile as demonstrated above in step #1.
Part #3.) Let’s now perform the process of building a DockerImage from the aforementioned Dockerfile :-
docker image build -t tomcat-df-aditya .
Note that, we had kept the name of the docker-image as “tomcat-df-aditya”.
Part #4.) Let’s check whether, our DockerImage has been formed well :-
docker images
Part #5.) Let’s launch a fresh container from this newly formed image
docker container run -it -p 8086:8080 <NAME_OF_DOCKER_IMAGE>
Part #6.) Let’s observe whether our webapp is running now. Note that, host port is 8086 :-
Now, we have our basic tomcat version 8.5.73 UP & RUNNING.
Part #7.) Let’s now log-in inside our container
docker container exec -it <container_id> bash
Question:- How come the container is taking us to the location “/usr/local/tomcat” as soon as we are logging inside this container ?
Answer:- It’s because the same has been defined inside the Dockerfile of the “tomcat” image, from which we have generated our image & container. See below, current working directory has been changed to “/usr/local/tomcat” in below Dockerfile of this particular image.
Question:- Now that, we have seen all building blocks, Kindly demonstrate the launch-process of a simple webapp through tomcat based Docker container with the help of Dockerfile :-
Answer:-
Part #1.) Let’s utilise the below shown Dockerfile for launching container containing tomcat and thereby deploying our WAR file into it :-
FROM tomcat:8.5.73-jdk8-openjdk
MAINTAINER Aditya Goel "adityagoel123@gmail.com"
EXPOSE 8080
RUN mv /usr/local/tomcat/webapps.dist/* /usr/local/tomcat/webapps/
WORKDIR /usr/local/tomcat/webapps/
COPY fleetman1.war .
RUN mv ./fleetman1.war ./ROOT.jar
ENV JAVA_OPTS="-Dspring.profiles.active=docker-demo"
CMD ["catalina.sh", "run"]
Note the following points :-
- EXPOSE command is just an indication that, tomcat within our container would be exposed on port 8080.
- With ENV JAVA_OPTS, we are setting the Java environment variables inside the container.
Part #2.) Let’s now head to our best friend terminal and change directory to the place, where we have our Dockerfile as demonstrated above in step #1.
Part #3.) Let’s now perform the process of building a DockerImage from the aforementioned Dockerfile :-
docker image build -t tomcat--webapp-aditya .
Note that, we had kept the name of the docker-image as “tomcat — webapp-aditya”.
Part #4.) Let’s check whether, our DockerImage has been formed well :-
docker images
Part #5.) Let’s launch a fresh container from this newly formed image :-
docker container run -itd -p 8088:8080 <NAME_OF_DOCKER_IMAGE>
Part #6.) Lets now login into our container :-
docker container exec -it 0c bash
Part #7.) Let’s observe whether our webapp is running now. Note that, host port is 8088 :-
Now, we have our web-application running on the tomcat through container.
Part #7.) Let’s now see our container :-
docker containers ps
Part #8.) Let’s see the logs of our container now :-
docker container logs 0c
Question:- Next, Kindly demonstrate the launch-process of a simple Spring-Boot based application through JDK based Docker container with the help of Dockerfile :-
Answer:-
Part #1.) Let’s search for a right Docker based Image (containing JDK) . We shall be using the OpenJDK version 8u312.
Part #2.) Let’s utilise the below-mentioned Dockerfile for launching container containing JDK and thereby deploying our JAR file into it :-
FROM openjdk:8u312-jdk
MAINTAINER Aditya Goel "adityagoel123@gmail.com"
EXPOSE 8080
WORKDIR /usr/local/bin/
COPY fleetman-0.0.1-SNAPSHOT.jar webapp.jar
CMD ["java", "-Dspring.profiles.active=docker-demo", "-jar", "webapp.jar"]
Part #3.) Let’s now head to our best friend terminal and change directory to the place, where we have our Dockerfile as demonstrated above in step #1.
Part #4.) Let’s now perform the process of building a DockerImage from the aforementioned Dockerfile :-
docker image build -t webapp-springboot-aditya .
Note that, we had kept the name of the docker-image as “webapp-springboot-aditya”.
Part #5.) Let’s check whether, our DockerImage has been formed well :-
docker images
Part #6.) Let’s launch a fresh container from this newly formed image :-
docker container run -itd -p 8089:8080 <NAME_OF_DOCKER_IMAGE>
Part #7.) Lets now login into our container :-
docker container exec -it d1 bash
Part #8.) Let’s verify, the JDK version in our container :-
Part #9.) Let’s observe whether our webapp is running now. Note that, host port is 8089 :-
Now, we have our web-application running based on the SpringBoot.
Part #10.) Let’s now see our container :-
docker containers ps
That’s all in this section. If you liked reading this blog, kindly do press on clap button multiple times, to indicate your appreciation. We would see you in next series.
References :-
- https://adityagoel123.medium.com/docker-for-devs-with-hands-on-part-4-b45848af2d8a
- https://adityagoel123.medium.com/sneak-view-into-docker-for-devs-part-2-2884dc04fae4
- https://adityagoel123.medium.com/sneak-view-into-docker-for-java-devs-part-1-b0388ecd5974
- https://adityagoel123.medium.com/sneak-view-into-docker-for-web-devs-part-2-eac68e3226
- https://adityagoel123.medium.com/sneak-view-into-docker-for-web-devs-45b4d1aff63
- https://github.com/adityagoel123/DockerBasedWebAppOnTomcat/
- https://github.com/adityagoel123/DockerBasedSpringBootAppln
- https://github.com/docker-library/tomcat/blob/f09adde460dd759217d661bd2d00f6623c0a3c09/8.5/jdk8/openjdk-bullseye/Dockerfile
- https://github.com/docker-library/docs/blob/master/openjdk/README.md#supported-tags-and-respective-dockerfile-links
- https://www.virtualpairprogrammers.com/training-courses/Docker-for-Java-Developers-training.html
- https://hub.docker.com/_/tomcat?tab=reviews
- https://forums.docker.com/t/tomcat-give-error-404/95130
- https://github.com/docker-library/docs/blob/master/tomcat/README.md#supported-tags-and-respective-dockerfile-links
- https://stackoverflow.com/questions/46400946/docker-how-to-copy-a-file-from-one-folder-in-a-container-to-another
- https://jhooq.com/docker-failed-to-compute-cache-key/
- https://www.javainuse.com/devOps/docker/docker-war
- https://stackoverflow.com/questions/32095186/how-to-deploy-webapp-or-war-file-in-tomcat-that-is-running-in-docker-container
- https://codefresh.io/docker-tutorial/create-docker-images-for-java/
- https://codefresh.io/docker-tutorial/create-docker-images-for-java/
- https://stackoverflow.com/questions/66146088/docker-failed-to-compute-cache-key-not-found-runs-fine-in-visual-studio
- https://stackoverflow.com/questions/46400946/docker-how-to-copy-a-file-from-one-folder-in-a-container-to-another
- https://github.com/moby/buildkit/issues/1647