Chapter 3: Dokerize Laravel App with Nginx and Postgres.
Tags: docker, postgres, database, webdev
Published: 2022-11-23 14:51:41

## Postgres SQL

It's time to set up our database in Docker. Because the app is relatively small and built on monolith architecture, so we will install it inside Docker.

Now we can go to our `/infra/pgsql` and add a new folder named `script` and then create `initdb.sh` inside it.

Initdb.sh will be used to create a script to create PG user and PG databases. In this case, my app is using two databases within the same DB instace.

So we first, create a function to create the user, database, and privilege. Then we can loop it over the number of databases we want to create.

**initdb.sh**
```
#!/bin/bash

set -e
set -u

function create_user_and_db() {
  local database=$1

	echo "  Creating user and database '$database'"
	psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL
	    CREATE USER $database;
	    CREATE DATABASE $database;
	    GRANT ALL PRIVILEGES ON DATABASE $database TO $database;
EOSQL
}

if [ -n "$POSTGRES_MULTIPLE_DATABASES" ]; then
	echo "Multiple database creation requested: $POSTGRES_MULTIPLE_DATABASES"
	for db in $(echo $POSTGRES_MULTIPLE_DATABASES | tr ',' ' '); do
		create_user_and_db $db
	done
	echo "Multiple databases created"
fi
```

If you want to see a different way to install PG in Docker, you can check [here](https://geshan.com.np/blog/2021/12/docker-postgres/).

Inside `pgsql` folder, we can create a Dockerfile

```
FROM postgres:14.1
COPY script/initdb.sh /docker-entrypoint-initdb.d/
```

The initdb.sh will be copied to `docker-entrypoint-initdb.d`, so it will automatically run when we run docker-compose.

So after we have added all of those items, here is the complete `docker-compose.yml`

```
version: "3.7"

networks:
  app-network:
    driver: bridge

services: 
  app:
    container_name: app
    build:
      context: ./infra/app
      dockerfile: Dockerfile
    image: php-laravel-7.0
    restart: unless-stopped
    tty: true
    working_dir: /var/www
    volumes: 
      - ./:/var/www
    networks: 
      - app-network

  db:
    container_name: pgsql
    build:
      context: ./infra/pgsql
      dockerfile: Dockerfile
    image: pgsql-docker
    restart: unless-stopped
    expose:
     - "5432"
    ports:
      - "5433:5432"
    volumes: 
      - ./infra/pgsql/script:/docker-entrypoint-initdb.d
      - ./infra/pgsql/data:/var/lib/postgresql/data
    environment:
      - POSTGRES_USER=${DB_USERNAME}
      - POSTGRES_MULTIPLE_DATABASES=main_db,logger_db // you change this
    networks:
      - app-network

  nginx:
    image: nginx:1.19.8-alpine
    container_name: nginx
    restart: unless-stopped
    tty: true
    ports: 
        - 8100:80
    volumes: 
        - ./:/var/www
        - ./infra/nginx/conf:/etc/nginx/conf.d
    networks: 
        - app-network
```
Now we can run `docker-compose build` then `docker-compose up -d`, if we don't see any error, so we can assume our docker set up is a success.

We are still not finished yet because we did manual DB migration, yes we didn't use Laravel migration.

We need to dump the DB manually like this. You can adjust the db dump path.
```
docker-compose exec -T db pg_restore -U postgres -d main_db < db_dump/dump-<DB NAME>-202203201444.sql
```

Because we are using 
`- ./infra/pgsql/data:/var/lib/postgresql/data` in our docker-compose, so we expect our database data to be persisted even if the docker is shut down.

One more thing, we need to run these two script to make our Laravel app working.
```
docker-compose exec -T app php artisan key:generate
```

```
docker-compose exec -T app composer install
```

If we want to run laravel db migration instead, we can run this command.
```
docker-compose exec -T app php artisan migrate
```

That's all from my post.