mirror of https://github.com/docker/docs.git
432 lines
15 KiB
Markdown
432 lines
15 KiB
Markdown
---
|
|
title: Use containers for Node.js development
|
|
linkTitle: Develop your app
|
|
weight: 20
|
|
keywords: node, node.js, development
|
|
description: Learn how to develop your Node.js application locally using containers.
|
|
aliases:
|
|
- /get-started/nodejs/develop/
|
|
- /language/nodejs/develop/
|
|
- /guides/language/nodejs/develop/
|
|
---
|
|
|
|
## Prerequisites
|
|
|
|
Complete [Containerize a Node.js application](containerize.md).
|
|
|
|
## Overview
|
|
|
|
In this section, you'll learn how to set up a development environment for your containerized application. This includes:
|
|
|
|
- Adding a local database and persisting data
|
|
- Configuring your container to run a development environment
|
|
- Debugging your containerized application
|
|
|
|
## Add a local database and persist data
|
|
|
|
You can use containers to set up local services, like a database. In this section, you'll update the `compose.yaml` file to define a database service and a volume to persist data.
|
|
|
|
1. Open your `compose.yaml` file in an IDE or text editor.
|
|
2. Uncomment the database related instructions. The following is the updated
|
|
`compose.yaml` file.
|
|
|
|
> [!IMPORTANT]
|
|
>
|
|
> For this section, don't run `docker compose up` until you are instructed to. Running the command at intermediate points may incorrectly initialize your database.
|
|
|
|
```yaml {hl_lines="26-51",collapse=true,title=compose.yaml}
|
|
# Comments are provided throughout this file to help you get started.
|
|
# If you need more help, visit the Docker Compose reference guide at
|
|
# https://docs.docker.com/go/compose-spec-reference/
|
|
|
|
# Here the instructions define your application as a service called "server".
|
|
# This service is built from the Dockerfile in the current directory.
|
|
# You can add other services your application may depend on here, such as a
|
|
# database or a cache. For examples, see the Awesome Compose repository:
|
|
# https://github.com/docker/awesome-compose
|
|
services:
|
|
server:
|
|
build:
|
|
context: .
|
|
environment:
|
|
NODE_ENV: production
|
|
ports:
|
|
- 3000:3000
|
|
|
|
# The commented out section below is an example of how to define a PostgreSQL
|
|
# database that your application can use. `depends_on` tells Docker Compose to
|
|
# start the database before your application. The `db-data` volume persists the
|
|
# database data between container restarts. The `db-password` secret is used
|
|
# to set the database password. You must create `db/password.txt` and add
|
|
# a password of your choosing to it before running `docker compose up`.
|
|
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
db:
|
|
image: postgres
|
|
restart: always
|
|
user: postgres
|
|
secrets:
|
|
- db-password
|
|
volumes:
|
|
- db-data:/var/lib/postgresql/data
|
|
environment:
|
|
- POSTGRES_DB=example
|
|
- POSTGRES_PASSWORD_FILE=/run/secrets/db-password
|
|
expose:
|
|
- 5432
|
|
healthcheck:
|
|
test: ["CMD", "pg_isready"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
volumes:
|
|
db-data:
|
|
secrets:
|
|
db-password:
|
|
file: db/password.txt
|
|
```
|
|
|
|
> [!NOTE]
|
|
>
|
|
> To learn more about the instructions in the Compose file, see [Compose file
|
|
> reference](/reference/compose-file/).
|
|
|
|
3. Open `src/persistence/postgres.js` in an IDE or text editor. You'll notice
|
|
that this application uses a Postgres database and requires some environment
|
|
variables in order to connect to the database. The `compose.yaml` file doesn't
|
|
have these variables defined yet.
|
|
4. Add the environment variables that specify the database configuration. The
|
|
following is the updated `compose.yaml` file.
|
|
|
|
```yaml {hl_lines="16-19",collapse=true,title=compose.yaml}
|
|
# Comments are provided throughout this file to help you get started.
|
|
# If you need more help, visit the Docker Compose reference guide at
|
|
# https://docs.docker.com/go/compose-spec-reference/
|
|
|
|
# Here the instructions define your application as a service called "server".
|
|
# This service is built from the Dockerfile in the current directory.
|
|
# You can add other services your application may depend on here, such as a
|
|
# database or a cache. For examples, see the Awesome Compose repository:
|
|
# https://github.com/docker/awesome-compose
|
|
services:
|
|
server:
|
|
build:
|
|
context: .
|
|
environment:
|
|
NODE_ENV: production
|
|
POSTGRES_HOST: db
|
|
POSTGRES_USER: postgres
|
|
POSTGRES_PASSWORD_FILE: /run/secrets/db-password
|
|
POSTGRES_DB: example
|
|
ports:
|
|
- 3000:3000
|
|
|
|
# The commented out section below is an example of how to define a PostgreSQL
|
|
# database that your application can use. `depends_on` tells Docker Compose to
|
|
# start the database before your application. The `db-data` volume persists the
|
|
# database data between container restarts. The `db-password` secret is used
|
|
# to set the database password. You must create `db/password.txt` and add
|
|
# a password of your choosing to it before running `docker compose up`.
|
|
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
db:
|
|
image: postgres
|
|
restart: always
|
|
user: postgres
|
|
secrets:
|
|
- db-password
|
|
volumes:
|
|
- db-data:/var/lib/postgresql/data
|
|
environment:
|
|
- POSTGRES_DB=example
|
|
- POSTGRES_PASSWORD_FILE=/run/secrets/db-password
|
|
expose:
|
|
- 5432
|
|
healthcheck:
|
|
test: ["CMD", "pg_isready"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
volumes:
|
|
db-data:
|
|
secrets:
|
|
db-password:
|
|
file: db/password.txt
|
|
```
|
|
|
|
5. Add the `secrets` section under the `server` service so that your application securely handles the database password. The following is the updated `compose.yaml` file.
|
|
|
|
```yaml {hl_lines="33-34",collapse=true,title=compose.yaml}
|
|
# Comments are provided throughout this file to help you get started.
|
|
# If you need more help, visit the Docker Compose reference guide at
|
|
# https://docs.docker.com/go/compose-spec-reference/
|
|
|
|
# Here the instructions define your application as a service called "server".
|
|
# This service is built from the Dockerfile in the current directory.
|
|
# You can add other services your application may depend on here, such as a
|
|
# database or a cache. For examples, see the Awesome Compose repository:
|
|
# https://github.com/docker/awesome-compose
|
|
services:
|
|
server:
|
|
build:
|
|
context: .
|
|
environment:
|
|
NODE_ENV: production
|
|
POSTGRES_HOST: db
|
|
POSTGRES_USER: postgres
|
|
POSTGRES_PASSWORD_FILE: /run/secrets/db-password
|
|
POSTGRES_DB: example
|
|
ports:
|
|
- 3000:3000
|
|
|
|
# The commented out section below is an example of how to define a PostgreSQL
|
|
# database that your application can use. `depends_on` tells Docker Compose to
|
|
# start the database before your application. The `db-data` volume persists the
|
|
# database data between container restarts. The `db-password` secret is used
|
|
# to set the database password. You must create `db/password.txt` and add
|
|
# a password of your choosing to it before running `docker compose up`.
|
|
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
secrets:
|
|
- db-password
|
|
db:
|
|
image: postgres
|
|
restart: always
|
|
user: postgres
|
|
secrets:
|
|
- db-password
|
|
volumes:
|
|
- db-data:/var/lib/postgresql/data
|
|
environment:
|
|
- POSTGRES_DB=example
|
|
- POSTGRES_PASSWORD_FILE=/run/secrets/db-password
|
|
expose:
|
|
- 5432
|
|
healthcheck:
|
|
test: ["CMD", "pg_isready"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
volumes:
|
|
db-data:
|
|
secrets:
|
|
db-password:
|
|
file: db/password.txt
|
|
```
|
|
|
|
6. In the `docker-nodejs-sample` directory, create a directory named `db`.
|
|
7. In the `db` directory, create a file named `password.txt`. This file will
|
|
contain your database password.
|
|
|
|
You should now have at least the following contents in your
|
|
`docker-nodejs-sample` directory.
|
|
|
|
```text
|
|
├── docker-nodejs-sample/
|
|
│ ├── db/
|
|
│ │ └── password.txt
|
|
│ ├── spec/
|
|
│ ├── src/
|
|
│ ├── .dockerignore
|
|
│ ├── .gitignore
|
|
│ ├── compose.yaml
|
|
│ ├── Dockerfile
|
|
│ ├── package-lock.json
|
|
│ ├── package.json
|
|
│ └── README.md
|
|
```
|
|
|
|
8. Open the `password.txt` file in an IDE or text editor, and specify a password
|
|
of your choice. Your password must be on a single line with no additional
|
|
lines. Ensure that the file doesn't contain any newline characters or other
|
|
hidden characters.
|
|
9. Ensure that you save your changes to all the files that you have modified.
|
|
10. Run the following command to start your application.
|
|
|
|
```console
|
|
$ docker compose up --build
|
|
```
|
|
|
|
11. Open a browser and verify that the application is running at
|
|
[http://localhost:3000](http://localhost:3000).
|
|
12. Add some items to the todo list to test data persistence.
|
|
13. After adding some items to the todo list, press `ctrl+c` in the terminal to
|
|
stop your application.
|
|
14. In the terminal, run `docker compose rm` to remove your containers.
|
|
|
|
```console
|
|
$ docker compose rm
|
|
```
|
|
|
|
15. Run `docker compose up` to run your application again.
|
|
|
|
```console
|
|
$ docker compose up --build
|
|
```
|
|
|
|
16. Refresh [http://localhost:3000](http://localhost:3000) in your browser and verify that the todo items persisted, even after the containers were removed and ran again.
|
|
|
|
## Configure and run a development container
|
|
|
|
You can use a bind mount to mount your source code into the container. The container can then see the changes you make to the code immediately, as soon as you save a file. This means that you can run processes, like nodemon, in the container that watch for filesystem changes and respond to them. To learn more about bind mounts, see [Storage overview](/manuals/engine/storage/_index.md).
|
|
|
|
In addition to adding a bind mount, you can configure your Dockerfile and `compose.yaml` file to install development dependencies and run development tools.
|
|
|
|
### Update your Dockerfile for development
|
|
|
|
Open the Dockerfile in an IDE or text editor. Note that the Dockerfile doesn't
|
|
install development dependencies and doesn't run nodemon. You'll
|
|
need to update your Dockerfile to install the development dependencies and run
|
|
nodemon.
|
|
|
|
Rather than creating one Dockerfile for production, and another Dockerfile for
|
|
development, you can use one multi-stage Dockerfile for both.
|
|
|
|
Update your Dockerfile to the following multi-stage Dockerfile.
|
|
|
|
```dockerfile {hl_lines="5-26",collapse=true,title=Dockerfile}
|
|
# syntax=docker/dockerfile:1
|
|
|
|
ARG NODE_VERSION=18.0.0
|
|
|
|
FROM node:${NODE_VERSION}-alpine as base
|
|
WORKDIR /usr/src/app
|
|
EXPOSE 3000
|
|
|
|
FROM base as dev
|
|
RUN --mount=type=bind,source=package.json,target=package.json \
|
|
--mount=type=bind,source=package-lock.json,target=package-lock.json \
|
|
--mount=type=cache,target=/root/.npm \
|
|
npm ci --include=dev
|
|
USER node
|
|
COPY . .
|
|
CMD npm run dev
|
|
|
|
FROM base as prod
|
|
RUN --mount=type=bind,source=package.json,target=package.json \
|
|
--mount=type=bind,source=package-lock.json,target=package-lock.json \
|
|
--mount=type=cache,target=/root/.npm \
|
|
npm ci --omit=dev
|
|
USER node
|
|
COPY . .
|
|
CMD node src/index.js
|
|
```
|
|
|
|
In the Dockerfile, you first add a label `as base` to the `FROM
|
|
node:${NODE_VERSION}-alpine` statement. This lets you refer to this build stage
|
|
in other build stages. Next, you add a new build stage labeled `dev` to install
|
|
your development dependencies and start the container using `npm run dev`.
|
|
Finally, you add a stage labeled `prod` that omits the dev dependencies and runs
|
|
your application using `node src/index.js`. To learn more about multi-stage
|
|
builds, see [Multi-stage builds](/manuals/build/building/multi-stage.md).
|
|
|
|
Next, you'll need to update your Compose file to use the new stage.
|
|
|
|
### Update your Compose file for development
|
|
|
|
To run the `dev` stage with Compose, you need to update your `compose.yaml`
|
|
file. Open your `compose.yaml` file in an IDE or text editor, and then add the
|
|
`target: dev` instruction to target the `dev` stage from your multi-stage
|
|
Dockerfile.
|
|
|
|
Also, add a new volume to the server service for the bind mount. For this application, you'll mount `./src` from your local machine to `/usr/src/app/src` in the container.
|
|
|
|
Lastly, publish port `9229` for debugging.
|
|
|
|
The following is the updated Compose file. All comments have been removed.
|
|
|
|
```yaml {hl_lines=[5,8,20,21],collapse=true,title=compose.yaml}
|
|
services:
|
|
server:
|
|
build:
|
|
context: .
|
|
target: dev
|
|
ports:
|
|
- 3000:3000
|
|
- 9229:9229
|
|
environment:
|
|
NODE_ENV: production
|
|
POSTGRES_HOST: db
|
|
POSTGRES_USER: postgres
|
|
POSTGRES_PASSWORD_FILE: /run/secrets/db-password
|
|
POSTGRES_DB: example
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
secrets:
|
|
- db-password
|
|
volumes:
|
|
- ./src:/usr/src/app/src
|
|
db:
|
|
image: postgres
|
|
restart: always
|
|
user: postgres
|
|
secrets:
|
|
- db-password
|
|
volumes:
|
|
- db-data:/var/lib/postgresql/data
|
|
environment:
|
|
- POSTGRES_DB=example
|
|
- POSTGRES_PASSWORD_FILE=/run/secrets/db-password
|
|
expose:
|
|
- 5432
|
|
healthcheck:
|
|
test: ["CMD", "pg_isready"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
volumes:
|
|
db-data:
|
|
secrets:
|
|
db-password:
|
|
file: db/password.txt
|
|
```
|
|
|
|
### Run your development container and debug your application
|
|
|
|
Run the following command to run your application with the new changes to the `Dockerfile` and `compose.yaml` file.
|
|
|
|
```console
|
|
$ docker compose up --build
|
|
```
|
|
|
|
Open a browser and verify that the application is running at [http://localhost:3000](http://localhost:3000).
|
|
|
|
Any changes to the application's source files on your local machine will now be
|
|
immediately reflected in the running container.
|
|
|
|
Open `docker-nodejs-sample/src/static/js/app.js` in an IDE or text editor and update the button text on line 109 from `Add Item` to `Add`.
|
|
|
|
```diff
|
|
+ {submitting ? 'Adding...' : 'Add'}
|
|
- {submitting ? 'Adding...' : 'Add Item'}
|
|
```
|
|
|
|
Refresh [http://localhost:3000](http://localhost:3000) in your browser and verify that the updated text appears.
|
|
|
|
You can now connect an inspector client to your application for debugging. For
|
|
more details about inspector clients, see the [Node.js
|
|
documentation](https://nodejs.org/en/docs/guides/debugging-getting-started).
|
|
|
|
## Summary
|
|
|
|
In this section, you took a look at setting up your Compose file to add a mock
|
|
database and persist data. You also learned how to create a multi-stage
|
|
Dockerfile and set up a bind mount for development.
|
|
|
|
Related information:
|
|
|
|
- [Volumes top-level element](/reference/compose-file/volumes/)
|
|
- [Services top-level element](/reference/compose-file/services/)
|
|
- [Multi-stage builds](/manuals/build/building/multi-stage.md)
|
|
|
|
## Next steps
|
|
|
|
In the next section, you'll learn how to run unit tests using Docker.
|