When we want decide to use Docker container we probably have multiple Docker containers. In that case each container has to communicate with each other and they must be of course in the same network. Docker container is in theory isolated from Host machine and other containers. To enable the communications, we need to create a network for Docker containers.
You can find the complete source code here
This is one of Docker learning series posts.
- Start Docker from scratch
- Docker volume
- Bind host directory to Docker container for dev-env
- Communication with other Docker containers
- Run multi Docker containers with compose file
- Container’s dependency check and health check
- Override Docker compose file to have different environments
- Creating a cluster with Docker swarm and handling secrets
- Update and rollback without downtime in swarm mode
- Container optimization
- Visualizing log info with Fluentd, Elasticsearch and Kibana
log-server
To test the network functionality we need to have at least two applications. I created small log server at first. Following code is the all.
import * as restify from "restify";
import * as winston from "winston";
const logger = winston.createLogger({
level: "info",
format: winston.format.json(),
transports: [
new winston.transports.Console(),
new winston.transports.File({ filename: 'server.log' }),
],
});
const server = restify.createServer();
let calledCount = 0;
server.get('/status', (req, res, next) => {
res.send(`Log called count: ${calledCount}`);
next();
});
server.post('/log', (req, res, next) => {
calledCount++;
try {
logger.info(`${req.body.name}: ${req.body.data}`);
res.send(201, "Created");
} catch (e) {
logger.error(`name: ${req.body?.name}, data: ${req.body?.data}`);
res.send(400, "Bad Request");
}
next();
});
server.use(restify.plugins.bodyParser());
const port = 80;
server.listen(port, function () {
logger.info(`${server.name} listening at ${server.url}`);
});
You can test if the log-server works. But build first.
cd log-server
npm install
npm run build
docker image build -t log-server .
docker container run --rm -p 8001:80 --name log-server log-server
$ curl -X POST -H "Content-Type:application/json" -d '{"name": "curl-test", "data": "log-test-data"}' http://localhost:8001/log
"Created"
log-server’s output is following.
$ docker container run --rm -p 8001:80 --name log-server log-server
{"message":"restify listening at http://[::]:80","level":"info"}
{"message":"curl-test: log-test-data","level":"info"}
restify-server
Second application is restify server. I copied sample code from restify and modified a little.
// Logger.ts
import * as http from "http";
import { URL } from "url";
export class Logger {
private readonly logUrl = new URL("/log", process.env.LOGGER_API_URL);
constructor(private name: string) { }
public log(message: string) {
const postData = JSON.stringify({
name: this.name,
data: message,
});
const options: http.RequestOptions = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData),
}
};
const req = http.request(this.logUrl, options, (res) => {
console.log(`STATUS: ${res.statusCode}`);
console.log(`HEADERS: ${JSON.stringify(res.headers)}`);
res.setEncoding('utf8');
res.on('data', (chunk) => {
console.log(`BODY: ${chunk}`);
});
res.on('end', () => {
console.log('No more data in response.');
});
});
req.on('error', (e) => {
console.error(`problem with request: ${e.message}`);
});
// Write data to request body
req.write(postData);
req.end();
}
}
// server.ts
import * as restify from "restify";
import { Logger } from "./Logger";
const server = restify.createServer();
const logger = new Logger("restify-server");
function respond(
req: restify.Request,
res: restify.Response,
next: restify.Next
) {
logger.log(`GET request with param [${req.params.name}]`);
res.send('hello ' + req.params.name);
next();
}
server.get('/hello/:name', respond);
server.head('/hello/:name', respond);
const port = 80;
server.listen(port, function () {
logger.log(`${server.name} listening at ${server.url}`);
});
cd restify-server
npm install
npm run build
docker image build -t restify-server .
Start the applications without network definition
Since restify-server posts data to log-server at start up log-server must start up first. And then, start restify-server.
$ docker container run --rm -p 8001:80 --name log-server log-server
{"message":"restify listening at http://[::]:80","level":"info"}
Run following command from different console.
$ docker container run --rm -p 8002:80 --name restify-server restify-server
problem with request: getaddrinfo ENOTFOUND log-server
It shows an error because we haven’t created the network for it. The network is completely isolated by default. Let’s create a network named log-test-nat
here to place both applications in the same network.
docker network create log-test-nat
Once network is created it needs to be specified by --network
option when executing docker run command. Let’s specify the network for both applications.
docker container run --rm -p 8001:80 --name log-server --network log-test-nat log-server
From different console
docker container run --rm -p 8002:80 --name restify-server --network log-test-nat restify-server
You can also execute the same command by npm run dstart
because I I defined it in package.json
. After restify-server starts up access to the server from browser. You can access to the server by http://localhost:8002/hello/foo-hoge
for example and log-server shows following message.
{"message":"restify-server: GET request with param [foo-hoge]","level":"info"}
I specified follwoing code in Dockerfile of restify-server. The host name is log-server
which I set with --name
option. This container name becomes DNS name of the container, so other container can find the host by the name.
ENV LOGGER_API_URL="http://log-server:80/"
Conclusion
It’s very easy to create network to communicate each other. Just create a named network by docker network create <network name>
before running applications and specify it with --network <network name>
when executing Docker container run command. However, the command is getting long when we introduce new functionality. We can create batch file or define script in package.json
for example but Docker offers another option Docker Compose
. Next post is for the functionality!
Comments