# 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.
