Docker

Docker Tutorial And Cheat Sheet

Learn Docker for QA automation, including Jenkins, MySQL, Flask app containers, bind mounts, Dockerfiles, custom images, and Docker Hub workflows.

Welcome to the Docker cheat sheet and tutorial. This guide walks through Docker commands and practical examples for running existing images, using volumes, building custom images, and pushing images to Docker Hub.

For QA engineers and automation engineers, Docker is useful because it lets you run databases, CI/CD tools, test applications, and disposable environments without manually installing everything on your machine.

Table Of Contents

Common Docker Commands

CommandWhat It Does
docker runRuns a container from an image.
docker pullPulls an image from a Docker registry.
docker buildBuilds an image from a Dockerfile.
docker psLists running containers.
docker stopStops a running container.
docker rmRemoves a stopped container.
docker imagesLists downloaded images.
docker rmiRemoves an image.
docker execRuns a command inside a running container.
docker run
docker pull
docker build
docker ps
docker stop
docker rm
docker images
docker rmi
docker exec

Using Docker To Run Applications From Existing Images

Running applications in Docker containers gives you consistent environments, isolation, and easier setup. This section covers several examples: Jenkins for CI/CD, MySQL for database testing, and a custom Flask To-Do application for web app practice.

Each example highlights important Docker concepts such as port mapping, environment variables, container naming, detached mode, and data persistence.

Running Jenkins In Docker

Jenkins is a CI/CD tool used to automate build, test, and deployment workflows. Running Jenkins in Docker gives you an isolated CI/CD environment that you can start, stop, and recreate quickly.

Method 1: Run Jenkins With Specific Ports

First, pull the Jenkins image from Docker Hub. If you skip this step, Docker will automatically pull the image when you run the container.

docker pull jenkins/jenkins:lts

Run Jenkins and map the container ports to known host ports:

docker run --name jenkins-container -p 8080:8080 -p 50000:50000 jenkins/jenkins:lts
OptionDescription
--name jenkins-containerAssigns a readable name to the container.
-p 8080:8080Maps host port 8080 to container port 8080 so Jenkins is available at http://localhost:8080.
-p 50000:50000Maps the Jenkins agent communication port.
jenkins/jenkins:ltsUses the long-term-support Jenkins image.

Method 2: Run Jenkins With Automatic Port Mapping

Docker's -P flag maps exposed container ports to random available host ports. This is useful when you do not care which host port gets used.

docker run --name jenkins-container -P jenkins/jenkins:lts

After running the command, check which ports were assigned:

docker ps

Then open Jenkins at http://localhost:[random_port].

Naming Containers

The --name option gives a container a specific name. This makes containers easier to identify, stop, remove, and inspect. If you do not name a container, Docker generates a random name.

Running MySQL In Docker

MySQL is a relational database. Running MySQL in Docker lets you create a consistent and isolated database environment for database testing, API testing, and automation practice.

Run MySQL With Environment Variables And Port Mapping

docker run --name mysql-container -e MYSQL_ROOT_PASSWORD=my-secret-pw -p 3306:3306 -d mysql:latest
OptionDescription
--name mysql-containerAssigns the name mysql-container to the running container.
-e MYSQL_ROOT_PASSWORD=my-secret-pwSets the root password for MySQL using an environment variable.
-p 3306:3306Maps host port 3306 to container port 3306.
-dRuns the container in detached mode in the background.
mysql:latestUses the official MySQL image. Docker pulls it automatically if needed.

Connect From MySQL Workbench

After running the MySQL container, you can connect to it from MySQL Workbench:

  1. Open MySQL Workbench and create a new connection.
  2. Use any connection name you prefer.
  3. Set hostname to localhost.
  4. Set port to 3306.
  5. Set username to root.
  6. Set password to my-secret-pw.
  7. Click Test Connection and save the connection if successful.

Connect From Inside The Container

You can also connect directly from inside the container with docker exec:

docker exec -it mysql-container mysql -uroot -p

This opens an interactive terminal in the running mysql-container, starts the MySQL client, and logs in as root. Enter my-secret-pw when prompted.

Verify The MySQL Connection

Once connected, run:

SHOW DATABASES;

If the command lists databases, your MySQL connection is working.

Running A Flask To-Do App In Docker

This example uses a custom Flask To-Do application published on Docker Hub as supersqa/todo-app-flask-docker-demo. Running this app in Docker provides a consistent environment for testing and development.

Method 1: Automatic Port Mapping

The simplest option is to use -P, which maps the container's internal port to a random available port on the host.

docker run --name todo-app -P -d supersqa/todo-app-flask-docker-demo
OptionDescription
--name todo-appAssigns the name todo-app to the container.
-PMaps exposed container ports to random available host ports.
-dRuns the container in detached mode.
supersqa/todo-app-flask-docker-demoUses the Flask To-Do app image from Docker Hub.

Find the assigned port:

docker port todo-app

Docker may show output like:

0.0.0.0:32768->5151/tcp

In that example, open http://localhost:32768.

Method 2: Specific Port Mapping

To make the app available at a known port, map port 5151 explicitly:

docker run --name todo-app -p 5151:5151 -d supersqa/todo-app-flask-docker-demo

Then open:

http://localhost:5151

Method 3: Environment Variables And Volume

For more advanced configuration, pass environment variables and mount a host directory:

docker run --name todo-app -p 5151:5151 -e FLASK_ENV=development -v $(pwd)/app-data:/app/data -d supersqa/todo-app-flask-docker-demo
OptionDescription
-e FLASK_ENV=developmentSets an environment variable inside the container.
-v $(pwd)/app-data:/app/dataMounts a host directory into the container for data persistence.

Stop And Remove The To-Do App

docker stop todo-app
docker rm todo-app

Using Docker Volumes

Docker volumes persist data used by and generated inside containers. Without persistence, data stored in a container's writable layer can disappear when the container is removed.

Docker provides three common storage patterns:

TypeDescription
Anonymous volumesCreated without a specific name. Useful for temporary storage.
Named volumesExplicitly named volumes that can be reused across containers.
Bind mountsMount a specific host directory or file into a container. Useful for development and direct access to files.

This tutorial focuses on bind mounts because they are practical for development, testing, configuration files, databases, and app data.

Using Bind Mounts With Jenkins

Bind mounts let Jenkins store configuration and job data on the host so it survives container restarts and removal.

docker run --name jenkins-container -v $(pwd)/jenkins_home:/var/jenkins_home -p 8080:8080 -p 50000:50000 -d jenkins/jenkins:lts
OptionDescription
-v $(pwd)/jenkins_home:/var/jenkins_homeMounts jenkins_home from the current host directory into Jenkins' home directory inside the container.
-p 8080:8080Makes Jenkins available at http://localhost:8080.
-p 50000:50000Maps the Jenkins agent port.
-dRuns the container in detached mode.

Using Bind Mounts With MySQL

Bind mounts are useful for persisting MySQL database files on the host.

docker run --name mysql-container -v $(pwd)/mysql_data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -p 3306:3306 -d mysql:latest
OptionDescription
-v $(pwd)/mysql_data:/var/lib/mysqlStores MySQL data in the host's mysql_data directory.
-e MYSQL_ROOT_PASSWORD=my-secret-pwSets the root password.
-p 3306:3306Maps MySQL port 3306 to the host.
-dRuns the container in detached mode.

Using Bind Mounts With A Flask To-Do App

Bind mounts can also persist app data from a custom web app.

docker run --name todo-app-container -v $(pwd)/app-tasks:/app/tasks -p 5151:5151 -d supersqa/todo-app-flask-docker-demo
OptionDescription
-v $(pwd)/app-tasks:/app/tasksMounts the host's app-tasks directory into the container at /app/tasks.
-p 5151:5151Makes the app available at http://localhost:5151.
-dRuns the container in detached mode.

Bind mounts are especially useful when containers need direct access to host files, configuration, database files, or development data.

Building Your Own Docker Images

Building custom Docker images lets you define your application's environment, dependencies, and runtime behavior. This helps applications run consistently across different machines and environments.

Docker Images And Dockerfiles

Docker images are the foundation of containers. They include the OS layer, libraries, dependencies, and application code needed to run the app.

A Dockerfile is a text file with instructions Docker uses to build an image. It makes the image creation process repeatable and consistent.

Create A Simple Dockerfile

Here is a basic Dockerfile for a Python Flask application:

# Use an official Python runtime as a parent image
FROM python:3.9-slim

# Set the working directory in the container
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 --no-cache-dir -r requirements.txt

# Make port 5000 available to the world outside this container
EXPOSE 5000

# Define environment variable
ENV NAME World

# Run app.py when the container launches
CMD ["python", "app.py"]
InstructionDescription
FROM python:3.9-slimUses a slim Python image as the base image.
WORKDIR /appSets /app as the working directory.
COPY . /appCopies the current directory into the image.
RUN pip install --no-cache-dir -r requirements.txtInstalls Python dependencies.
EXPOSE 5000Documents that the app listens on port 5000.
ENV NAME WorldSets an environment variable.
CMD ["python", "app.py"]Runs the Flask app when the container starts.

Build The Docker Image

Run this command in the same directory as the Dockerfile:

docker build -t my-flask-app .
OptionDescription
-t my-flask-appTags the image with the name my-flask-app.
.Sets the build context to the current directory.

Dockerfile Best Practices

  • Keep Dockerfiles simple and readable.
  • Use official base images when possible.
  • Start from minimal trusted base images to reduce image size and vulnerability surface.
  • Minimize unnecessary layers where practical.
  • Never hardcode secrets, passwords, tokens, or private keys in Dockerfiles.
  • Use environment variables or secret management for sensitive configuration.
  • Use multi-stage builds when a complex build process would otherwise make the final image large.

Use Environment Variables At Runtime

Environment variables can configure a container without rebuilding the image.

docker run -e NAME=OpenAI my-flask-app

The -e NAME=OpenAI option sets the NAME environment variable inside the container.

Install External Dependencies

If your app requires external dependencies, install them in the Dockerfile:

RUN pip install --no-cache-dir requests

The --no-cache-dir flag avoids storing unnecessary pip cache files in the image.

Pushing Images To Docker Hub

After building a custom Docker image, you can push it to Docker Hub for sharing or deployment.

docker push my-flask-app

Make sure you are logged in to Docker Hub before pushing.

For a real Docker Hub repository, the image usually needs to be tagged with your Docker Hub username and repository name:

docker tag my-flask-app your-dockerhub-username/my-flask-app:latest
docker push your-dockerhub-username/my-flask-app:latest

Conclusion

You have now covered the core Docker workflow:

  • Running containers from existing images
  • Mapping ports
  • Naming containers
  • Passing environment variables
  • Using bind mounts for persistence
  • Building custom Docker images with Dockerfiles
  • Pushing images to Docker Hub

Docker simplifies application setup and creates consistent environments across machines. For QA automation, this means you can spin up test databases, CI/CD tools, demo apps, and disposable environments quickly and reliably.

Free Software Testing Fundamentals

If you are learning Docker as part of your QA or automation path, start with the testing foundations too.

The free Software Testing Fundamentals course covers:

  • Testing basics, test cases, and bug reporting
  • SQL and database testing
  • API testing
  • Jira and real team workflows

Start Learning Free

Docker Tutorial And Cheat Sheet | SuperSQA