150 lines
		
	
	
	
		
			7.2 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			150 lines
		
	
	
	
		
			7.2 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
---
 | 
						|
tags: [docker]
 | 
						|
---
 | 
						|
 | 
						|
# Creating a Docker image
 | 
						|
 | 
						|
We create a new image with `docker build...`
 | 
						|
 | 
						|
The key components of a build:
 | 
						|
 | 
						|
- A Dockerfile
 | 
						|
- An asset directory (the **build context**) containing the Dockerfile and all
 | 
						|
  resources needed for the build.
 | 
						|
 | 
						|
## Syntax
 | 
						|
 | 
						|
Here is an example of a Dockerfile that builds a container for running a Python
 | 
						|
app:
 | 
						|
 | 
						|
```Dockerfile
 | 
						|
# Use an official Python runtime as a parent image
 | 
						|
FROM python:3.8-slim
 | 
						|
 | 
						|
# Set the working directory to /app
 | 
						|
WORKDIR /app
 | 
						|
 | 
						|
# Copy the current directory contents into the container at /app
 | 
						|
COPY . /app
 | 
						|
 | 
						|
# Install any needed packages specified in requirements.txt
 | 
						|
RUN pip install --trusted-host pypi.python.org -r requirements.txt
 | 
						|
 | 
						|
# Make port 80 available to the world outside this container
 | 
						|
EXPOSE 80
 | 
						|
 | 
						|
# Define environment variable
 | 
						|
ENV NAME World
 | 
						|
 | 
						|
# Run app.py when the container launches
 | 
						|
CMD ["python", "app.py"]
 | 
						|
 | 
						|
```
 | 
						|
 | 
						|
### Main syntax explained
 | 
						|
 | 
						|
| Keyword   | Role                                                                                                                                                                                                                                                                   |
 | 
						|
| --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
 | 
						|
| #         | Lines starting with '#' are comments, providing explanations or context for the Dockerfile.                                                                                                                                                                            |
 | 
						|
| `FROM`    | Specifies the base image used to build the new image. In this case, it's using the official Python 3.8 slim image.                                                                                                                                                     |
 | 
						|
| `WORKDIR` | Sets the working directory for any subsequent instructions in the Dockerfile. Here, it's set to '/app'. Everything after a `WORKDIR` line, all instructions will be executed in this directory. If it doesn't exist, Docker will create it. Can have multiple.         |
 | 
						|
| `COPY`    | Copies files or directories from the source (in this case, the current directory) to the destination (in this case, '/app') within the Docker image. The source is the build context. We are copying from the build context to the container when we use this keyword. |
 | 
						|
| `ADD`     | Same as `COPY` but can be passed a tarball or a URL                                                                                                                                                                                                                    |
 | 
						|
| `RUN`     | Executes a command and commits the result as a new layer in the image. In this example, it installs packages specified in the 'requirements.txt' file using pip.                                                                                                       |
 | 
						|
| `EXPOSE`  | Informs Docker that the container listens on the specified network ports at runtime. In this case, port 80.                                                                                                                                                            |
 | 
						|
| `ENV`     | Sets an environment variable in the image. In this example, the variable 'NAME' is set to 'World'.                                                                                                                                                                     |
 | 
						|
| `CMD`     | Specifies the command to run when the container starts. Here, it runs 'app.py' using Python. Note that there can only be one CMD instruction in a Dockerfile.                                                                                                          |
 | 
						|
| `USER`    | The default user will be `root`. This is not good for security. Have to choose a distribution image that allows you to change user. For example: `USER: nobody:nogroup`. Ubuntu allows for this.                                                                       |
 | 
						|
| `LABEL`   | Metadata that you want to add to the image to be viewable when image is inspected, e.g. `LABEL maintainer=tactonbishop@gmail.com`                                                                                                                                      |
 | 
						|
 | 
						|
### Another example
 | 
						|
 | 
						|
The following Dockerfile creates a frontend React application:
 | 
						|
 | 
						|
```Dockerfile
 | 
						|
# Use the official Node.js image as the base image
 | 
						|
FROM node:14-alpine
 | 
						|
 | 
						|
# Set the working directory to /app
 | 
						|
WORKDIR /app
 | 
						|
 | 
						|
# Copy the package.json and package-lock.json files
 | 
						|
COPY package*.json ./
 | 
						|
 | 
						|
# Install dependencies
 | 
						|
RUN npm ci
 | 
						|
 | 
						|
# Copy the rest of the application code
 | 
						|
COPY . .
 | 
						|
 | 
						|
# Expose the port the app will run on
 | 
						|
EXPOSE 3000
 | 
						|
 | 
						|
# Start the React development server
 | 
						|
CMD ["npm", "start"]
 | 
						|
```
 | 
						|
 | 
						|
### Two modes of `RUN`: shell and exec
 | 
						|
 | 
						|
The RUN command in a Dockerfile has two forms: the "exec" form and the "shell"
 | 
						|
form. Both forms are used to execute commands during the build process, but they
 | 
						|
have different syntax and behavior.
 | 
						|
 | 
						|
Exec form is written as `RUN ["executable", "param1", "param2", ...]`. This form
 | 
						|
executes the command directly without invoking a shell. As a result, shell
 | 
						|
processing features like environment variable substitution, pipes, and redirects
 | 
						|
are not available. It is the preferred form when you need to run a command
 | 
						|
without relying on shell behavior or when you want to avoid shell-related
 | 
						|
issues, such as variable substitution or command injection.
 | 
						|
 | 
						|
Shell form is written as `RUN command param1 param2 ....` This form executes the
 | 
						|
command within a shell, which is /bin/sh -c on Linux and cmd /S /C on Windows.
 | 
						|
It allows for shell processing, enabling environment variable substitution,
 | 
						|
pipes, redirects, and other shell features. This form is preferred when you need
 | 
						|
to use shell features or when you want to chain multiple commands together.
 | 
						|
 | 
						|
## Environmental variables
 | 
						|
 | 
						|
> ENV instructions in a Dockerfile are used to define environment variables that
 | 
						|
> can be accessed by the processes running inside the container. These variables
 | 
						|
> can be used to configure the behavior of the application, pass parameters, or
 | 
						|
> store sensitive information like API keys.
 | 
						|
 | 
						|
```Dockerfile
 | 
						|
# Use an official Node.js runtime as a parent image
 | 
						|
FROM node:14-alpine
 | 
						|
 | 
						|
# Set the working directory to /app
 | 
						|
WORKDIR /app
 | 
						|
 | 
						|
# Copy package.json and package-lock.json into the container
 | 
						|
COPY package*.json ./
 | 
						|
 | 
						|
# Install any needed packages specified in package.json
 | 
						|
RUN npm ci
 | 
						|
 | 
						|
# Copy the rest of the application code
 | 
						|
COPY . .
 | 
						|
 | 
						|
# Set environment variables
 | 
						|
ENV PORT=8000
 | 
						|
ENV API_KEY=my_secret_key
 | 
						|
 | 
						|
# Expose the port the app will run on
 | 
						|
EXPOSE 8000
 | 
						|
 | 
						|
# Run the app
 | 
						|
CMD ["npm", "start"]
 | 
						|
```
 | 
						|
 | 
						|
In this example, two environment variables are defined: PORT and API_KEY. These
 | 
						|
variables can be accessed in the application code using process.env.PORT and
 | 
						|
process.env.API_KEY in Node.js, for example.
 | 
						|
 | 
						|
To override the environment variables defined in the Dockerfile when running the
 | 
						|
container, you can use the -e flag followed by the variable name and its new
 | 
						|
value in the docker run command:
 | 
						|
 | 
						|
```sh
 | 
						|
docker run -e PORT=8080 -e API_KEY=new_secret_key -p 8080:8000 <image_name>
 | 
						|
```
 |