📃In this article we will figure it out, how to deploy your own app using docker and nginx, for our app we will use the following technologies:
🌐 For frontend (my repository): Next.js is a popular open-source React framework that enables developers to build server-rendered and static web applications with ease. It offers features like automatic code splitting, server-side rendering (SSR), static site generation (SSG), and API routes, which enhance performance and SEO. Next.js simplifies the development process by providing a file-based routing system and built-in support for CSS and TypeScript, making it a powerful choice for creating modern web applications.
⚙️ For backend (my repository): Nest.js is a progressive Node.js framework for building efficient, scalable server-side applications. It leverages TypeScript and incorporates modern design patterns, such as modular architecture and dependency injection, to promote maintainability and testability. With built-in support for GraphQL, WebSockets, and microservices, Nest.js is ideal for developing robust APIs and enterprise-level applications. Its extensible architecture allows integration with various libraries and tools, making it a versatile choice for backend development.
🗄️ For database: PostgreSQL is a powerful, open-source relational database management system (RDBMS) known for its robustness, extensibility, and compliance with SQL standards. It supports advanced data types, complex queries, and transactions, making it suitable for a wide range of applications. With features like ACID compliance, full-text search, and support for JSON and GIS data, PostgreSQL is favored for its performance, reliability, and ability to handle large volumes of data. Its active community and rich ecosystem of extensions further enhance its capabilities, making it a popular choice for developers and organizations.
Sometimes developers confuse Nest and Next😀
Ok, let's move on and do it!💪
📑Create docker network
The fist of all to create a common network for feauture containers
First of all, it is necessary to create and check a common network for future docker containers via command:
docker network create -d bridge yuit-net
, where are the following parameters:
- yuit-net - the name of our network
- bridge - the default network driver
- -d or --driver - this flag allows you to specify which network driver docker should use to create the network
- docker network ls - for check network
And in our terminal we can see all networks (including ours)
PS ...\portfolio-yues-nestjs-docker> docker network create -d bridge yuit-net
6019f719ee8bcd39cf0406a795f5a61a531756ce29c9a53974868d7797ed19e7
PS ...\portfolio-yues-nestjs-docker> docker network ls
NETWORK ID NAME DRIVER SCOPE
33c0431165ec bridge bridge local
295269f446db host host local
801fdcaabbb4 none null local
6019f719ee8b yuit-net bridge local
📑Create docker container for database
Next step we need to create container for our database PostgreSQL via:
docker run --network=yuit-net --name yuit-chart-db-host --rm -d -p 5432:5432 -i -t -e POSTGRES_DB=yuit-chart-db -e POSTGRES_USER=admin -e POSTGRES_PASSWORD=adminyuitpassword postgres
, where are the following parameters:
- --network=yuit-net - it's our docker network
- --name yuit-chart-db-host - it's a custom name to the container for data source option in our backend project (we will consider this below)
- --rm - this option tells docker to automatically remove the container when it stops
- -d - this flag runs the container in detached mode
- -p 5432:5432 - this option maps port 5432(first) of the host machine to port 5432(second) of the container
- -i - this flag stands for "interactive" mode. It keeps the standard input (stdin) open even if not attached, allowing you to interact with the container if needed
- -t - this flag allocates a pseudo-TTY (terminal) for the container, which is useful for running interactive applications. It is often used in conjunction with -i.
- -e POSTGRES_DB=yuit-chart-db - this option sets an environment variable inside the container. Here, it creates a PostgreSQL database named yuit-chart-db
- -e POSTGRES_USER=admin - this environment variable sets the username for the PostgreSQL database
- -e POSTGRES_PASSWORD=adminyuitpassword - this environment variable sets the password for the PostgreSQL user specified in the previous parameter
- postgres - it's the official PostgreSQL image from Docker Hub
And via command docker ps -a to check the DB container
PS ...\portfolio-yues-nestjs-docker> docker run --network=yuit-net --name yuit-chart-db-host --rm -d -p 5432:5432 -i -t -e POSTGRES_DB=yuit-chart-db -e POSTGRES_USER=admin -e POSTGRES_PASSWORD=adminyuitpassword postgres
PS ...\portfolio-yues-nestjs-docker> docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2ef9f2d7daa6 postgres "docker-entrypoint.s…" 5 seconds ago Up 5 seconds 0.0.0.0:5432->5432/tcp yuit-chart-db-host
❔ We may also connect to our DB, for example, via Database Tool: DBeaver
And we see our DB with the name yuit-chart-db
📑Create docker image and container for backend
After we have created our DB, we can create a docker image of backend.
For that:
1️⃣We need to create our Dockerfile, it's needed for describe our image, for example
# build app
FROM node:20.16-alpine AS build
WORKDIR /app
COPY . /app
ENV DATABASE_HOST=yuit-chart-db-host
RUN yarn install
RUN echo "Build is ok! Go to next layer!"
RUN yarn build
EXPOSE 8080
# start migration and api
CMD npm run migration:prod && npm run start:prod
2️⃣After that we can build image of backend, via command:
docker build . -t yuit-chart-backend-image -f infra/docker/Dockerfile
, where are the following parameters:
- the dot (.) - indicates that the current directory should be used as the context for the build
- -t yuit-chart-backend-image - it's name of your image
- -f infra/docker/Dockerfile - it's directory of our Dockerhfile
3️⃣The next step is run container:
docker run --network=yuit-net --name yuit-chart-backend -d -p 127.0.0.1:8080:8080/tcp yuit-chart-backend-image
, where are the following parameters:
- --network=yuit-net - it's our docker network
- --name yuit-chart-backend - this flag assigns a name to the container, i.e.
yuit-chart-backend
- -d - this stands for detached mode
- -p 127.0.0.1:8080:8080/tcp - this option is used to publish a container's port to the host, where:
- 8080:8080 indicates that port 8080 on the host will be mapped to port 8080 on the container.
- /tcp specifies the protocol to use (in this case, TCP). This part is optional, as TCP is the default protocol
- yuit-chart-backend-image - it's the name of the Docker image
❔ We can check our contaner via command docker ps -a
or to see containers in the docker desktop
We may also select our data from the DB, because we have run migrations in the Dockerfile. To do this, just run the select command in the DBeaver:
SELECT id, data
FROM public.chart;
SELECT *
FROM public.__migrations;
4️⃣After running the backend container, we can test the api through url: http://localhost:8080/data_chart
📑 Create docker image and container for frontend
Finally, we need to create an image and run a container for the frontend.
1️⃣ Let's add settings for the web server - nginx, for example:
Add these settings to the file conf.d
http {
server {
listen 8080;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri /index.html;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
}
events {}
2️⃣We need to create our Dockerfile, for example:
# build app
FROM node:20.16-alpine as build
WORKDIR /app
COPY . /app
RUN yarn
RUN echo "Build is ok! Go to next layer!"
RUN yarn deploy
# build server
FROM nginx:alpine as normal
# copy the build folder from react to the root of nginx
COPY --from=build /app/build /usr/share/nginx/html
COPY infra/docker/conf.d /etc/nginx/nginx.conf
RUN echo "Nginx is ok!"
# expose port 3000 to the outer world
EXPOSE 3000
# start nginx
CMD ["nginx", "-g", "daemon off;"]
3️⃣After that we can build image, via command:
docker build -t yuit-chart-frontend-image --target normal -f infra/docker/Dockerfile .
, where are the following parameters:
- -t yuit-chart-backend-image - it's image name
- -f infra/docker/Dockerfile - it's directory of our Dockerhfile
- --target normal - it's needed for build only a part of the Dockerfile, which can be useful for optimizing the build process and reducing image size
- the dot (.) - indicates that the current directory should be used as the context for the build
4️⃣The next step is run container:
docker run --network=yuit-net --name yuit-chart-frontend --rm -itd -p 127.0.0.1:3000:8080/tcp yuit-chart-frontend-image
, where are the following parameters:
- --network=yuit-net - it's our docker network
- --name yuit-chart-frontend - this flag assigns a name to the container
- --rm - this option tells Docker to automatically remove the container when it exits
- -itd - this stands for
i
- interactive mode,t
- allocates a pseudo-TTY andd
- detached mode- -p 127.0.0.1:3000:8080/tcp - this option is used to publish a container's port to the host, where:
- 3000:8080 indicates that port 3000 on the host will be mapped to port 8080 on the container
- /tcp specifies the protocol to use (in this case, TCP). This part is optional, as TCP is the default protocol
- yuit-chart-frontend-image - it's the name of the Docker image
5️⃣After running the frontend container, we can test the api through http://localhost:3000/
My examples:
Thanks for reading and feedback!🤝
Top comments (0)