You are on page 1of 8

Develop Intelligence – Docker Creating Custom Docker Images

Agenda: Creating Custom Docker Images


 Dockerfile and Building Docker Images
 Breaking down and understanding dockerfile indepth

Creating Image from current state of Container


Base Image  Container  Add files and Folder  Committed the Container  New Image  New Container

1. Start a container from the image nginx


docker run -d -p 8080:80 nginx
2. Get the list of containers and note the Container Id
docker ps -a
3. Enter into the shell of container
docker exec -it <container id> bash
4. Execute the following shell commands in the Container instance
cd /usr/share/nginx/html
echo "Hello, How are you…" > hello.html
exit
5. Also you can copy content from Host to Container
In some directory put HTML files – Our custom website build locally.
docker cp . <container-id>:/usr/share/nginx/html
6. Create an image from container ID where we created our file:

docker commit <container id> mynginx:v1


7. Note that the new image by name mynginx:v1 is created
docker images
8. Start a new container using the newly created image
docker run -p 8080:80 mynginx:v1
curl http://localhost:8080/hello.html

Creating Image using Dockerfile

 A Dockerfile is a text file which contains a series of commands or instructions. You need to use an existing
image as the starting point for your app, but you decide which one.
 These instructions are executed in the order in which they are written.
 Execution of these instructions takes place on a base image.
 On building the Dockerfile, the successive actions form a new image from the base parent image.
1. Create a d:\Demo\Dockerfile:
Develop Intelligence – Docker Creating Custom Docker Images
FROM nginx
WORKDIR /usr/share/nginx/html
RUN echo "Hello, How are you…" > hello.html
COPY . .
a) The first instruction must be FROM. This instruction initializes a new build stage and sets the Base Image for
the remaining instructions. The multi-arch tags pull either Windows or Linux containers depending on the
Docker for Windows container mode.
b) The WORKDIR instruction sets the working directory. If the directory doesn't exist, it's created. In this case,
WORKDIR is set to the HelloWorld directory. The WORKDIR instruction wont create a new layer in the image
but will add metadata to the image config.
c) The COPY instruction copies new files or directories from the source path and adds them to the destination
container filesystem.
a. COPY <src>... <dest>
b. COPY ["<src>",... "<dest>"] (this form is required for paths containing whitespace)
d) RUN executes the instruction
Build the Image
D:\demo>docker build -t sandeep/mynginx:v1 .
Note: Image names must be unique and are specified in the format <repository>/<image>:<tag>.

Run the Image – Create the container


D:\demo>docker run sandeep/mynginx:v1

Show the running process in the container (Container must be running and not exited)

D:\demo>docker top <Container ID>

Understanding CMD and ENTRYPOINT:


e) The ENTRYPOINT instruction allows the container to run as an executable.
a. ENTRYPOINT should be defined when using the container as an executable.
b. ENTRYPOINT echo "Hi, your ENTRYPOINT instruction in Shell Form !"
c. ENTRYPOINT ["/bin/echo", "Hi, your ENTRYPOINT instruction in Exec Form !"]

CMD vs EntryPoint
FROM ubuntu
CMD [ "echo", "THIS IS COMMAND…" ]
Note the o/p of following commands
 docker run sandeep/demo #o/p=THIS IS COMMAND…
Develop Intelligence – Docker Creating Custom Docker Images
 docker run sandeep/demo ls #ls is a command and o/p=Lists all folders

FROM ubuntu
ENTRYPOINT ["echo", "THIS IS ENTRYPOINT..."]
Note the o/p of following commands
 docker run sandeep/demo #o/p=THIS IS ENTRYPOINT…
 docker run sandeep/demo ls #o/p=THIS IS ENTRYPOINT…ls

Overriding EntryPoint
If an image has an ENTRYPOINT if you pass an argument it, while running container it won't override the existing
entrypoint, it will append what you passed with the entrypoint.
To override the existing ENTRYPOINT you should user --entrypoint flag when running container.

$ docker container run --entrypoint "echo" sandeep/demo "Hello, Welcome to my docker session! "

NOTE: Dockerfile should specify at least one of CMD or ENTRYPOINT commands.

Create an Image from locally developed Project


1. Create a .NET 6 app for Dockerization
mkdir HelloWorldApp
cd HelloWorldApp
dotnet new mvc
dotnet run
dotnet publish -c Release -o out

2. Open the folder in Visual Studio Code:


Code .

3. Add the following to HelloWorldApp.csproj


<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
</ItemGroup>

4. Add a new file to the root folder: Dockerfile


FROM mcr.microsoft.com/dotnet/aspnet:6.0
WORKDIR /app
#COPY out /app
Develop Intelligence – Docker Creating Custom Docker Images
COPY ["out", "/app"]
ENTRYPOINT ["dotnet", "HelloWorldApp.dll"]

5. Build and run


docker build -t sandeepsoni/hello-world .
docker run --rm sandeepsoni/hello-world

Creating a docker file to include build/publish


FROM mcr.microsoft.com/dotnet/sdk:6.0
WORKDIR /app
COPY . .
RUN dotnet restore
RUN dotnet build
RUN dotnet publish -o /out
WORKDIR /out
ENTRYPOINT ["dotnet", "HelloWorldApp.dll"]

Optimized Dockerfile:
FROM mcr.microsoft.com/dotnet/sdk:6.0
WORKDIR /app
# copy project and restore
COPY *.csproj .
RUN dotnet restore
COPY . .
RUN dotnet build
RUN dotnet publish -c Release -o /out
WORKDIR /out
ENTRYPOINT ["dotnet", "HelloWorldApp.dll"]

To make your build context as small as possible add a .dockerignore file to your project folder and copy the
following into it.
.dockerignore
bin/
obj/
out
Develop Intelligence – Docker Creating Custom Docker Images
Execute the following command to build the container image

docker build -t sandeepsoni/helloworld:v2 .

JAVA Example
Create a file: ./demo/HelloWorld.java
package demo;
public class HelloWorld
{
public static void main(String[] args)
{
System.out.println("HelloWorld from Docker");
}
}

Dockerfile:
FROM openjdk:11-jdk
WORKDIR /src
COPY . .
RUN javac -d /out demo/HelloWorld.java
WORKDIR /out
CMD ["java", "demo.HelloWorld"]

Dockerfile for Java Project using Maven


FROM maven
WORKDIR /myapp
COPY pom.xml .
RUN mvn clean install
COPY . .
RUN mvn compiler:compile
RUN mvn compiler:testCompile
RUN mvn package
ENTRYPOINT ["java","-jar","target/demo.jar"]

Python Example
hello.py

import sys
Develop Intelligence – Docker Creating Custom Docker Images
import platform
print("Hello from Python")
print(platform.platform())

Dockefile
FROM python:3.8
WORKDIR /app
COPY *.py .
CMD ["python", "hello.py"]

Node JS Example
1. Create a folder /myapp
2. Create package.json file
{
"name": "web_app",
"version": "1.0.0",
"description": "Node.js on Docker",
"author": "First Last <first.last@example.com>",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"dependencies": {
"express": "^4.16.1"
}
}
3. Run: npm install (Requires NodeJS to be installed on your machine)
4. Create server.js
'use strict';
const express = require('express');
// Constants
const PORT = 8080;
const HOST = '0.0.0.0';
// App
const app = express();
app.get('/', (req, res) => {
Develop Intelligence – Docker Creating Custom Docker Images
res.send('Hello World');
});
app.listen(PORT, HOST);
console.log(`Running on http://${HOST}:${PORT}`);

5. Create a Dockerfile
FROM node:14
# Create app directory
WORKDIR /usr/src/app

# Install app dependencies


# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm@5+)
COPY package*.json ./

RUN npm install


# If you are building your code for production
# RUN npm ci --only=production

# Bundle app source


COPY . .

EXPOSE 8080
CMD [ "node", "server.js" ]

6. Create a .dockerignore
node_modules
npm-debug.log

7. Build a docker image


docker build -t node-web-app .

8. Run the Image to create a container.

docker run -p 8080:8080 -d node-web-app

9. Test the container


Develop Intelligence – Docker Creating Custom Docker Images
curl localhost:8080

Summary:
1. Always include build steps in Dockerfile. So that the DevOps Pipeline doesnt have to bother about the build
tasks.
2. Always put commands related to files not changing frequently on top so that those commands can come from
cache.
3. Write a multi-stage Dockefile. Copy output from build stage to final stage.
4. Exclude files/folders to be copied using .dockerignore

You might also like