From https://www.codeschool.com/screencasts/build-a-node-app-with-postgres-and-docker # Step 1: Nginx * Run nginx * in foreground * `docker run -p 81:80 --name web nginx` * in foreground and removing it when stopped * `docker run -p 81:80 --name web --rm nginx` * in background * `docker run -p 81:80 --name web -d nginx` * foreground, mounting the `nginx/html` directory: ```bash docker run --rm \ -p 81:80 \ --name web \ --mount type=bind,source="$PWD"/nginx/html,target=/usr/share/nginx/html \ nginx # or... docker run --rm \ -p 81:80 \ --name web \ -v "$PWD"/nginx/html,/usr/share/nginx/html \ nginx ``` * Enter the container: `docker exec -it web /bin/bash` * Build a local image from the `Dockerfile` ```bash docker build -t osinet/nginx:latest . ``` * Run the newly built image: ```bash docker run --rm \ -p 81:80 \ --name web \ --mount type=bind,source=$PWD/nginx/html,target=/usr/share/nginx/html \ osinet/nginx ``` * List images * All except intermediates: `docker images` * All including intermediates: `docker images -a` * Images with this name: `docker images osinet/nginx` # Step 2: Node.js app ```bash mkdir node cd node # edit Dockerfile docker build -t node-app . docker run -p 8888:8888 \ -v $PWD/node/src:/usr/src/app/src \ --name voting-node \ --rm \ node-app ``` # Step 3: PostgreSQL * Build and run the container ```bash mkdir postgres cd postgres # edit Dockerfile docker build -t voting-pg . docker run -p 5432:5432 \ --name voting-pg \ --rm \ voting-pg ``` * Enter the container with a PG client: ```bash # Without the -U, PG will try to use undeclared used root. docker container exec -it voting-pg psql -U postgres ``` * In `psql` in the container, list databases, create table, list tables: ```postgresql \l CREATE TABLE votes ( id INTEGER PRIMARY KEY, number_of_votes INTEGER, option_name VARCHAR(20) ); \dt ``` * Now we have a table: ``` List of relations Schema | Name | Type | Owner --------+-------+-------+---------- public | votes | table | postgres (1 row) ``` * Insert initial data ```postgresql INSERT INTO votes (id, number_of_votes, option_name) VALUES (1, 13, 'sandwiches'); INSERT INTO votes (id, number_of_votes, option_name) VALUES (2, 21, 'tacos'); SELECT * FROM votes; ``` * Results: ``` id | number_of_votes | option_name ----+-----------------+------------- 1 | 0 | sandwiches 2 | 0 | tacos (2 rows) ``` # Step 4: PG in Node app * To reach PG, the app needs to know the address. To get to it from inside the container where the app runs, look for the `gateway` value in the results of `docker bridge`: ``` [...snip...] "IPAM": { "Driver": "default", "Options": null, "Config": [ { "Subnet": "172.17.0.0/16", "Gateway": "172.17.0.1" } ] }, [...snip...] ``` * We then know that the IP to use in `client.connect()` will be `172.17.0.1`, at least in the current configuration. Will probably have to come from the outside for more flexibility. * Posting data to update: ```bash curl -d"yourVote=sandwiches" http://localhost:8888/vote curl -d"yourVote=tacos" http://localhost:8888/vote curl -d"yourVote=invalid" http://localhost:8888/vote ``` Step 5: persistence * Initialize PG as described on the image page, by adding a SQL file to the container from the host into the `docker-entrypoint-initdb.d/` directory. COPY seed.sql /docker-entrypoint-initdb.d/ * Redefine the image-provided volume pointing to the PG data: VOLUME /var/lib/postgresql/data * Rebuild container cd postgres docker container build -t voting-pg . * Run it. Beware: we can't have a `.gitkeep` in the `postgres/data` directory, which will prevent PG from starting in that directory. But if we don't have it, the directory will have to be created, because git won't save it. ```bash cd postgres if [ ! -d data ]; then mkdir data fi docker container run \ --name voting-pg \ -p 9000:5432 \ -v $PWD/data:/var/lig/postgresql/data \ --rm -d \ voting-pg ``` * Run the app ```bash cd node docker container run \ --name voting-node \ -p 8888:8888 \ -v $PWD/src:/usr/src/app/src \ --rm -d \ voting-node ``` * When stopping the PG container, the node app will crash and not restart. Just touch the `server.js` file and `nodemon` in the node container will restart it. This is only good for a development workflow: a production version should handle disconnects.