How to package VueJS + NodeJS + MongoDB application in Docker

How to package VueJS + NodeJS + MongoDB application in Docker
As you can see from the previous article, I worked with different projects. The first days in a new team usually go the same way: the backender sits down to me and performs the magic steps to install and deploy the application. Docker is indispensable for front-end developers, because. The backend is often written in a wide range of PHP/Java/Python/C# stacks and the front doesn't need to distract the back each time to install and deploy everything. Only in one place I saw a bunch of Docker-Jenkins with a transparent deployment, logs, screwed with autotests.

A lot of detailed articles have been written about docker. This article will focus on deploying a Single Page Application using VueJS / Vue Router, the server part in the form of a RESTful API with NodeJS, and MongoDB is used as a database. Docker Compose is used to describe and run multiple container applications.

Why you need Docker

Docker allows you to automate the process of deploying an application. The developer no longer needs to install programs on his own, deal with version incompatibility on his machine. It is enough to install Docker and type 1-2 commands into the console. It is most convenient to do this on Linux.

Getting started

Set Docker and docker compose

Folder structure

We create 2 folders for client and server applications. A file with the .yml extension is a config Docker Composewhere the application containers are defined and linked.
docker-compose.yml:

version: "3"
services:
  mongo:
    container_name: mongo
    hostname: mongo
    image: mongo
    ports:
      - "27017:27017"
  server:
    build: server/
    #command: node ./server.js #здСсь ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠ΅Ρ€Π΅Π·Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ CMD ΠΈΠ· Dockerfile Π² /server
    ports:
      - "3000:3000"
    links:
      - mongo
  client:
    build: client/
    #command: http-server ./dist #здСсь ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠ΅Ρ€Π΅Π·Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ CMD ΠΈΠ· Dockerfile Π² /client
    network_mode: host
    ports:
      - "8089:8089"
    depends_on:
      - server

We create 3 services in docker: for NodeJS, MongoDB and for statics on Vue. To connect client to server added depends on server. To link MongoDB with the server API, use links mongo. Server, client, mongo are the names of the services.

VueJS Client

In the folder /client the application is located on VueJS. Application created with vue cli. When building an image, the client application is built into a set of static files in a folder /dist. The Dockerfile describes a set of commands for building an image:

FROM node:10
WORKDIR /client
COPY ./package*.json ./
RUN npm install
RUN npm install -g http-server
COPY . .
RUN npm run build
EXPOSE 8081
CMD ["npm", "test:dev"]

Note that package.json is copied and installed separately from the rest of the project files. This is done for performance so that the contents of the /node_modules folder are cached on rebuild. Each command line is cached separately.

At the end, when the container is started, the command is executed npm run dev. This command is described in package.json:


"scripts": {
	 "test:dev": "http-server dist -p 8081 -c 1 --push-state"
}

To run files from a folder /dist, globally set http-server, and in dev-dependencies package spa-http-serverto make Vue Router work correctly. The --push-state flag redirects to index.html. The -c flag with a value of 1 second has been added to http-server did not cache scripts. This is a test example, on a real project it is better to use nginx.

Create a field in the Vuex store apiHost: 'http://localhost:3000', where the NodeJS Api port is written. The client part is ready. Now all requests from the client to the back end go to this url.

NodeJS Server API

In the folder /server create server.js and Dockerfile:


FROM node:10
WORKDIR /server
COPY ./package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]

Π’ server.js is indicated url for database const url = 'mongodb://mongo:27017/';. We allow cross-domain requests from the client:


const clientUrl = 'http://localhost:8081';
const corsOptions = {
  origin: clientUrl,
  optionsSuccessStatus: 200, // some legacy browsers (IE11, various SmartTVs) choke on 204
};
app.use(cors());
app.all('/*', (req, res, next) => {
  res.header('Access-Control-Allow-Origin', clientUrl);
  res.header('Access-Control-Allow-Headers', 'X-Requested-With');
  next();
});
  app.get('/getProducts', cors(corsOptions), (req, res) => {
    products.getContent
      .then(data => res.json(data), err => res.json(err));
  });
  app.get('/getUsers', cors(corsOptions), (req, res) => {
    db.getUsers()
      .then(data => res.json(data), err => res.json(err));
  });

Conclusion

Now go to the project directory and run docker-compose build for imaging and docker-compose up to run containers. The command will lift 3 containers: server, client, mongo. For a NodeJS server, you can configure hot-reload by linking it to the user folder. And the client is under development to run locally with hot reload, running separately server ΠΈ mongo. To start a separate service, just specify its name docker-compose up client. Don't forget to do it sometimes prune and removal of containers (containers), networks (networks) and images (images) to free up resources.

You can see the full code here. The project is still under development.

Source: habr.com

Add a comment