# How to Dockerize Applications with Docker Compose (Using SQLite and Flask)

Below is a set of instructions for Dockerizing a Flask and SQLit project. This can also be done with other mixture of technologies such as using Postgres instead. This is intended to be a guide for other projects as well.

### Step 1: Set Up a `.dockerignore` File

Before building the Docker image, create a `.dockerignore` file to exclude unnecessary files and directories from the Docker image.

1. **Create a `.dockerignore` file** in the root of your project.
2. **Add common files to ignore**:

   ```dockerignore
   *.pyc
   __pycache__
   .git
   *.md
   docker-compose.yml
   *.py
   .env
   *.db
   ```

This will ensure unnecessary files like Python bytecode, Git history, and documentation aren't copied into your Docker image.

***

### Step 2: Create a `Dockerfile`

The `Dockerfile` defines how to build the Docker image for your app.

#### 2.1 Create a `Dockerfile`

1. **Create a `Dockerfile`** in the root directory of your project.
2. **Add the following configuration** for building the image:

   ```dockerfile
   # Use the official Python image from DockerHub
   FROM python:3.11-slim

   # Set the working directory in the container
   WORKDIR /usr/src/app

   # Install system dependencies (e.g., gcc for compiling Python libraries)
   RUN apt-get update && apt-get install -y --no-install-recommends gcc

   # Copy the requirements.txt file into the container
   COPY requirements.txt .

   # Install Python dependencies
   RUN pip install --no-cache-dir -r requirements.txt

   # Copy the rest of the application files into the container
   COPY . .

   # Expose the port the app will run on (default Flask port)
   EXPOSE 5000

   # Set environment variables (e.g., Flask app entry point)
   ENV FLASK_APP=main.py

   # Command to run the Flask app
   CMD ["flask", "run", "--host=0.0.0.0", "--port=5000"]
   ```

#### Explanation of the `Dockerfile`:

* **FROM python:3.11-slim**: Use a minimal Python image.
* **WORKDIR /usr/src/app**: Set the working directory inside the container.
* **RUN apt-get update && apt-get install gcc**: Install system dependencies.
* **COPY requirements.txt .**: Copy your `requirements.txt` file into the container.
* **RUN pip install --no-cache-dir -r requirements.txt**: Install Python dependencies.
* **COPY . .**: Copy all project files (excluding those in `.dockerignore`) into the container.
* **EXPOSE 5000**: Expose port `5000`, which is where Flask will run.
* **CMD \["flask", "run", "--host=0.0.0.0", "--port=5000"]**: Start the Flask application.

***

### Step 3: Create a `docker-compose.yml` File

For SQLite, you don’t need to set up a database service in Docker Compose because SQLite is just a file-based database. You’ll only need to configure the web app service.

#### 3.1 Create a `docker-compose.yml` File

1. **Create a `docker-compose.yml` file** in the root directory of your project.
2. **Add the following configuration** for your web app:

   ```yaml
   version: "3.8"

   services:
     web:
       build: .
       ports:
         - "5000:5000"
       environment:
         - FLASK_APP=main.py
       volumes:
         - ./data:/usr/src/app/data
   ```

#### Explanation of `docker-compose.yml`:

* **version**: Specifies the version of the Docker Compose file format. We are using version `3.8`.
* **services**: Defines the services (containers) for your application.
  * **web**: The Flask application container.
    * **build**: Tells Docker Compose to build the image from the current directory (which includes the `Dockerfile`).
    * **ports**: Maps port `5000` on your local machine to port `5000` in the container.
    * **environment**: Sets the environment variable `FLASK_APP=main.py`, which tells Flask to use `main.py` as the entry point.
    * **volumes**: Maps a local directory (`./data`) to a directory in the container (`/usr/src/app/data`). This is where the SQLite database file will be stored. This ensures the database persists between container restarts.

***

### Step 4: Build and Run the Application Using Docker Compose

Now that your `Dockerfile` and `docker-compose.yml` are set up, you can build and run your Flask application along with SQLite.

#### 4.1 Build and Start the Containers

1. Open a terminal and navigate to the directory where your `docker-compose.yml` file is located.
2. Run the following command to build the images and start the containers:

   ```bash
   docker-compose up --build
   ```

   The `--build` flag will rebuild the images if there are changes in your `Dockerfile`.
3. Once the containers are up and running, you can access your application in a web browser at `http://localhost:5000`.

#### 4.2 Run Containers in Detached Mode (Optional)

If you want to run the containers in the background, use the `-d` flag:

```bash
docker-compose up -d --build
```

This will start the containers in the background and allow you to continue using the terminal.

#### 4.3 Stop the Containers

To stop the containers and remove the associated networks, use the following command:

```bash
docker-compose down
```

***

### Step 5: Using SQLite with Flask

Since you're using SQLite, the database file will be stored on the host machine and mapped to a directory inside the container (`./data:/usr/src/app/data` in the `docker-compose.yml`). By default, Flask with SQLite will create a file-based database (e.g., `app.db`).

1. Ensure your Flask app is configured to use the SQLite database file from the mounted volume. For example, in your `main.py` file, you might have:

   ```python
   import sqlite3
   from flask import Flask

   app = Flask(__name__)

   # SQLite database file path
   DATABASE = '/usr/src/app/data/app.db'

   def get_db():
       conn = sqlite3.connect(DATABASE)
       return conn

   @app.route('/')
   def index():
       conn = get_db()
       cursor = conn.cursor()
       cursor.execute('SELECT * FROM users')
       users = cursor.fetchall()
       conn.close()
       return f'Users: {users}'

   if __name__ == "__main__":
       app.run(debug=True)
   ```
2. The `DATABASE` path is set to `/usr/src/app/data/app.db`, which is inside the container at `/usr/src/app/data`, but is mapped to a directory (`./data`) on the host. This means your SQLite database will be stored in the `./data` folder on your host machine, and the container will be able to read/write from it.

***

### Step 6: Push Docker Images to Docker Hub (Optional)

If you want to share your Docker images or deploy your app, you can push the image to Docker Hub.

#### 6.1 Tag the Docker Image

Tag your image with your Docker Hub username and repository name:

```bash
docker tag your-image-name yourusername/your-image-name:latest
```

#### 6.2 Push the Image

Push the tagged image to Docker Hub:

```bash
docker push yourusername/your-image-name:latest
```

***

### Additional Notes

* **Database Persistence**: By using a volume to store the SQLite database file, you ensure that your data persists even if you stop and remove the container.
* **Scaling with Docker Compose**: If you need to scale your Flask app or add more services later, Docker Compose allows you to easily define and scale multiple instances of your services.
* **Backup SQLite**: You can backup the SQLite database by copying the `./data` directory from your host system.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://martian1337.gitbook.io/notes/notes/product-security-engineering/devsecops/docker/how-to-dockerize-applications-with-docker-compose-using-sqlite-and-flask.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
