Introduction
This post is going to describe how I created a frontend for the private docker registry made in part 1.
Docker setup
uconn/express image
Because I wanted to use docker for this project, the first thing I needed to do was create another container that would run the express server. I tried to keep the image I made for this task fairly straightforward. Perhaps I'll post more technical details later, but briefly it....
- creates a /project directory to work in
- exposes ports at 3000 and 3001
- installs dependencies from a package.json file
- starts the server
docker-compose.yml
With this image for express, I could create a new entry in the docker-compose.yml file. The new service looks like this...
server:
image: uconn/express
container_name: registry-server
ports:
- "3000:3000"
environment:
NODE_ENV: development
restart: always
volumes:
- ./:/project
All of these properties were explained in Part 1. So, the whole file looks like this -
version: '3'
services:
registry:
image: registry:2
container_name: registry
ports:
- "5000:5000"
environment:
REGISTRY_AUTH: htpasswd
REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm
volumes:
- ./auth:/auth
- ./mnt/registry:/var/lib/registry
restart: always
server:
image: uconn/express
container_name: registry-server
ports:
- "3000:3000"
environment:
NODE_ENV: development
restart: always
volumes:
- ./:/project
The image is pre-configured to execute the command npm run start. So any start command that is added to the package.json file will be used automatically! In this case for development, I wanted to make sure I could run both the server and webpack. Next, I'll show how I started that process.
Server setup
Before writing any code, it's important to get a few things out of the way.
- adding dependencies for the server
- setting up npm tasks
- creating a few files and folders
Starting dependencies
To get started I wanted to make sure that I could
- get a server running (and keep it running) and serve some static content
- have some nice logging features
- be able to run npm tasks in parallel
- test a 'hello world' api route
I'll leave webpack and most of the frontend for the next section.
To start, install dependencies with the following commands
npm init
(to set up the package.json)npm install axios express
npm install --save-dev morgan nodemon npm-run-all
That's it!
Starting tasks
Next you need to add some tasks to the scripts section of the package.json. If there's no scripts section, that's ok. Add it in!
The scripts needed are going to:
- use nodemon to start a server and keep it running
- use webpack to watch our files (no, we haven't added this yet, I'll come back to it later)
- run these tasks in parallel (which will also happen later)
{
"scripts": {
"develop:server": "nodemon server.js",
"develop:webpack": "webpack --watch",
"start": "npm-run-all --parallel develop:server",
}
}
Hello server! Getting an express server started.
To start, create a server.js file at the root of your project. At the top of that file, bring in
- axios
- express
- and the username/password from the .env.js file that was created by the auth script from Part 1.
// server.js
const axios = require('axios')
const express = require('express')
const morgan = require('morgan')
const { USERNAME, PASSWORD } = require('./.env')
Next, I like to create a section where I can keep track of everything going on in the server environment. More will be added to this section later, but for now below the require statements....
/**
*
* Prepare the environment
*
*/
const PORT = 3000;
// this will come in handy later
// for develpoment vs production
const { env: { NODE_ENV } } = process;
Below that, it's time to
- create the express server
- enable logging
- and enable serving static assets
To do that, you'll create an express app and use the use method along with morgan and the express.static method.
/**
*
* begin working with the express server
*
*/
// create the express server app
const app = express();
// enable logging with morgan
app.use(morgan('combined'));
// serve assets from the /public directory
app.use(express.static('public'));
The express.static
method will now serve any static assets inside the public folder. So anything you want visible in the browser should go there.
The last thing you need to do is actually start the server. Because right now it isn't doing anything. To do that, at the very end of the server.js file, add:
/**
*
* begin listening to the app on port 3000
*
*/
app.listen(PORT, () => {
console.log(`listening on ${PORT}`)
});
Now when the docker container is run, the server will automatically be built and begin listening and serving files from the public folder on localhost:3000. At this point, the whole file should look like this....
const axios = require('axios');
const express = require('express');
const morgan = require('morgan');
const { USERNAME, PASSWORD } = require('./.env');
const PORT = 3000;
const { env: { NODE_ENV } } = process;
const app = express();
app.use(morgan('combined'));
app.use(express.static('public');
app.listen(PORT, () => {
console.log(`listening on ${PORT}`)
})
Conclusion
At this point, the container is ready to serve files because the host port and directory are mapped to the docker container. But there's still a problem.
The front end can't yet communicate with the registry container that has all the images.
So that's the next post! I'll get into a little bit of docker networking and sending requests from the browser to the registry container and back.