Let's glue it all together
This is part 10 of the series: How to create your own website based on Docker.Let's recap: We've created the backend containers consisting of a mongodb container and a ioJS/hapiJS container. We've also created the nginx/Angular 2.0 frontend container that makes use of the new backend.
As mentioned in the 4th part of this series we've defined that every request must go through an nginx reverse proxy. This proxy decides where the requests go to and what services are accessible from outside. So in order to make the whole setup available from the web, you need to configure the nginx reverse proxy that will route all requests to the proper docker container.
Source code
All files mentioned in this series are available on Github, so you can play around with it! :)Talking about container links again
Remember that we have linked containers together? And that we don't know the IP addresses, because Docker takes care of that and reserves them while creating the container?That's bad for a reverse proxy, since it needs to know where to route the requests to - but there's a good thing: IP addresses and ports are available as environment variable within each container. Bad thing: nginx configurations can't read environment variables! So using links makes creating this container hard and more complex than it actually should be - but there's a solution for that of course, which we will cover that later in that post.
So what does this container have to do?
Well, that's pretty simple... it needs to glue everything together, so it needs to collect all services that should be accessible from outside.So in our case we'd need an nginx configuration for:
- Our REST-API container based on ioJS & hapiJS
- Our frontend container based on nginx and Angular 2.0
We don't want to expose:
- Our mongodb container
- Our ubuntu base container
Let's get started - creating the nginx image
Creating the nginx image is basically the same every time. Let's create a new directory called /opt/docker/nginx-reverse-proxy/ and within this new directory we'll create other directories called config & html and our Dockerfile:
# mkdir -p /opt/docker/projectwebdev/config/So just create your /opt/docker/nginx-reverse-proxy/Dockerfile with the following content:
# mkdir -p /opt/docker/projectwebdev/html/
# > /opt/docker/projectwebdev/Dockerfile
# Pull base image.Source: https://github.com/mastix/project-webdev-docker-demo/blob/master/nginx-reverse-proxy/Dockerfile
FROM docker_ubuntubase
ENV DEBIAN_FRONTEND noninteractive
# Install Nginx.
RUN \
add-apt-repository -y ppa:nginx/stable && \
apt-get update && \
apt-get install -y nginx && \
rm -rf /var/lib/apt/lists/* && \
chown -R www-data:www-data /var/lib/nginx
# Define mountable directories.
VOLUME ["/etc/nginx/certs", "/var/log/nginx", "/var/www/html"]
# Define working directory.
WORKDIR /etc/nginx
# Copy all config files
COPY config/default.conf /etc/nginx/conf.d/default.conf
COPY config/nginx.conf /etc/nginx/nginx.conf
COPY config/config.sh /etc/nginx/config.sh
RUN ["chmod", "+x", "/etc/nginx/config.sh"]
# Copy default webpage
RUN rm /var/www/html/index.nginx-debian.html
COPY html/index.html /var/www/html/index.html
COPY html/robots.txt /var/www/html/robots.txt
# Define default command.
CMD /etc/nginx/config.sh && nginx
This Dockerfile also uses our Ubuntu base image, installs nginx and bakes our configuraton into our nginx container.
What is this html folder for?
Before looking into the configuration we'll cover the easy stuff first. :)While creating the directories you might have asked yourself why you need to create an html folder?! Well, that's simple: Since we're currently only developing api.project-webdev.com and blog.project-webdev.com we need a place to go when someone visits www.project-webdev.com - that's what this folder is for. If you don't have such a use case, you can also skip it - so this is kind of a fallback strategy.
The HTML page is pretty simple:
<!DOCTYPE html>
<html>
<head>
<title>Welcome to this empty page!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to this empty page!</h1>
<p>If you see this page, you'll see that it is empty.</p>
<p><em>Will this change soon...? Hell yeah it will! ;)</em></p>
</body>
</html>
So let's put this code into the following file nginx-reverse-proxy/html/index.html.
The nginx configuration
Now it's gettingAs mentioned before, our nginx container needs to route all requests based on the URL to our containers.
So we need two routes/locations
- api.project-webdev.com routes to my Docker REST API container
- blog.project-webdev.com routes to my Docker blog container
- BLOG_IP:BLOG_PORT
- BLOGAPI_IP:BLOGAPI_PORT
So you need a config file called /opt/docker/nginx-reverse-proxy/config/default.conf that contains your nginx server configuration:
upstream blog {## End api.project-webdev.com ##
server BLOG_IP:BLOG_PORT; #Blog
}
upstream blog-api {
server BLOGAPI_IP:BLOGAPI_PORT; #Blog-API
}
## Start blog.project-webdev.com ##
server {
listen 80;
server_name blog.project-webdev.com;
access_log /var/log/nginx/nginx-reverse-proxy-blog.access.log;
error_log /var/log/nginx/nginx-reverse-proxy-blog.error.log;
root /var/www/html;
index index.html index.htm;
## send request back to blog ##
location / {
proxy_pass http://blog;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
proxy_redirect off;
proxy_buffering off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
## End blog.project-webdev.com ##
## Start api.project-webdev.com ##
server {
listen 80;
server_name api.project-webdev.com*;
access_log /var/log/nginx/nginx-reverse-proxy-blog-api.access.log;
error_log /var/log/nginx/nginx-reverse-proxy-blog-api.error.log;
## send request back to blog api ##
location / {
proxy_pass http://blog-api;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
proxy_redirect off;
proxy_buffering off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# send the CORS headers
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Origin' 'http://blog.project-webdev.com';
}
}
This configuration file contains two locations, one that redirects to our blog (upstream blog {[..]}) and to our api (upstream blog-api{[...]}). As mentioned before, we're going to replace the IP and the port soon. :)
So what's happening is that every request against blog.project-webdev.com will be redirected to the corresponding upstream:
server {The same works for the REST API:
listen 80;
server_name blog.project-webdev.com;
[...]
location / {
proxy_pass http://blog;
[...]
}
}
server {
listen 80;
server_name api.project-webdev.com;
[...]
location / {
proxy_pass http://blog-api;
[...]
}
}
Using docker's environment variables
In order to use docker's environment variables we need to run a script every time the container starts. This script will check the default.conf file that you have just created and replaces your placeholders with the values from the environment variables; after that it will start nginx.See the last line of the dockerfile that triggers the script execution:
CMD /etc/nginx/config.sh && nginxLet's recap quickly: As mentioned in previous posts, Docker creates environment variables with IP and port information when you link containers together. These variables contain all information that you need to access your containers - and that's exactly what we want to do here.
The following script will replace our custom placeholders in our default.conf file with the corresponding values from the environment variables that Docker has created for us, so let's create the aforementioned /opt/docker/nginx-reverse-proxy/config/config.sh file:
#!/bin/bashThis script uses the basic sed (stream editor) command to replace the strings.
# Using environment variables to set nginx configuration
# Settings for the blog
echo "START UPDATING DEFAULT CONF"
[ -z "${BLOG_PORT_8081_TCP_ADDR}" ] && echo "\$BLOG_PORT_8081_TCP_ADDR is not set" || sed -i "s/BLOG_IP/${BLOG_PORT_8081_TCP_ADDR}/" /etc/nginx/conf.d/default.conf
[ -z "${BLOG_PORT_8081_TCP_PORT}" ] && echo "\$BLOG_PORT_8081_TCP_PORT is not set" || sed -i "s/BLOG_PORT/${BLOG_PORT_8081_TCP_PORT}/" /etc/nginx/conf.d/default.conf
[ -z "${BLOGAPI_PORT_3000_TCP_ADDR}" ] && echo "\$BLOGAPI_PORT_3000_TCP_ADDR is not set" || sed -i "s/BLOGAPI_IP/${BLOGAPI_PORT_3000_TCP_ADDR}/" /etc/nginx/conf.d/default.conf
[ -z "${BLOGAPI_PORT_3000_TCP_PORT}" ] && echo "\$BLOGAPI_PORT_3000_TCP_PORT is not set" || sed -i "s/BLOGAPI_PORT/${BLOGAPI_PORT_3000_TCP_PORT}/" /etc/nginx/conf.d/default.conf
echo "CHANGED DEFAULT CONF"
cat /etc/nginx/conf.d/default.conf
echo "END UPDATING DEFAULT CONF"
See the following example, that demonstrates how the IP address for the blog is being replaced:
[ -z "${BLOG_PORT_8081_TCP_ADDR}" ] && echo "\$BLOG_PORT_8081_TCP_ADDR is not set" || sed -i "s/BLOG_IP/${BLOG_PORT_8081_TCP_ADDR}/" /etc/nginx/conf.d/default.conf
- First it checks whether the BLOG_PORT_8081_TCP_ADDR exists as environment variable
- If that is true, it will call the sed command, which looks for BLOG_IP in the /etc/nginx/conf.d/default.conf file (which has been copied from our Docker host into the image - see Dockerfile)
- And will then replace it with the value from the environment variable BLOG_PORT_8081_TCP_ADDR.
And that's all the magic! ;)
So when the script has run, it will have replaced the placeholders in our config file so that it looks like this:
CHANGED DEFAULT CONF
upstream blog {
server 172.17.0.14:8081; #Blog
}
nginxreverseproxy_1 |
upstream blog-api {
server 172.17.0.10:3000; #Blog-API
}
... and therefore our nginx reverse proxy is ready to distribute our requests to our containers, since it knows their port and ip address now! :)
Ok, since we have now created all our containers it's about time to start them up in the next post! :)
This information should reach more people.
ReplyDeleteThanks for sharing. Bedigitech is famous for Web Development Services in Gurgaon. Find the most useful, imaginative, technologically advanced, and user-friendly custom websites with us.
ReplyDeleteThanks for sharing. BEglobalus is one of the leading Digital Marketing Company in Los Angeles. We are a highly experienced boutique agency that gives our clients outcomes that change the game.
ReplyDeletesiirt
ReplyDeletevan
hakkari
kastamonu
kütahya
G3GBKQ
kuşadası
ReplyDeletemilas
çeşme
bağcılar
adana
QORC8
karşıyaka transfer
ReplyDeleteakbük transfer
balıkesir transfer
ayvalık transfer
aliağa transfer
K8XJLQ