Wednesday, November 26, 2014

Running Multiple Websites on Single Docker Host


     It's known that containers, and specifically Linux containers, are not new. Tech giants such as Oracle, HP and IBM have been using containers for decades. In recent years, though, the open source project Docker has gained popularity as an alternative, or complement to virtualization. 

      One of the major benefits of containers is portability. Containers can run on top of virtual machines, or bare metal servers. They can run on-premises or in the cloud. This has made one of the earliest popular use cases of containers be around software development. Coders can write applications, place it in a container, and then the application can be moved across various environments, as it is encapsulated inside the container. 


     In the web world quite often is when a single physical server hosts several websites with different domain names. In the case of ordinary linux server, for instance - Apache, this problem is easily solved with the help of virtual hosts. However, docker implies that on single machine multiple containers are deployed. This post will explain how to get multiple docker containers running websites on port 80 using HAProxy as a reverse proxy. This makes it possible to run multiple websites on different domains on a single public ip of the host.



First launch the containers which run different websites. In our example we will use two demo containers with simple index.html pages and apache servers.

$ # Run hello world php demo container (test1.domain.com)
$ docker run -d repo/helloworld1
b4b232141b74
$ docker inspect -f "{{.NetworkSettings.IPAddress}}" b4b232141b74
172.17.0.26

$ # Run wordpress container (test2.domain.com)
$ docker run -d repo/helloworld2
f8aab7bc1e8f
$ docker inspect -f "{{.NetworkSettings.IPAddress}}" f8aab7bc1e8f
172.17.0.25

     Now we need to create our haproxy configuration to configure HAproxy as reverse proxy for our docker containers. Because HAProxy is also running inside a container we need to be able to access the hello-world and wordpress container by their private ip accessible from all containers. We got this IP using the command: 

 docker inspect -f "{{.NetworkSettings.IPAddress}}" $CONTAINERID.  

Make sure to note down these IPs as they will be used in the haproxy.cfg file.

$ # On the host(not container) create directory containing our haproxy config file
$ mkdir ~/haproxy-config

$ # Create ~/haproxy-config/haproxy.cfg
$ vim ~/haproxy-config/haproxy.cfg
global
        log 127.0.0.1   local0
        log 127.0.0.1   local1 notice
        user haproxy
        group haproxy
        # daemon

defaults
        log     global
        mode    http
        option  httplog
        option  dontlognull
        option forwardfor
        option http-server-close
        contimeout 5000
        clitimeout 50000
        srvtimeout 50000
        errorfile 400 /etc/haproxy/errors/400.http
        errorfile 403 /etc/haproxy/errors/403.http
        errorfile 408 /etc/haproxy/errors/408.http
        errorfile 500 /etc/haproxy/errors/500.http
        errorfile 502 /etc/haproxy/errors/502.http
        errorfile 503 /etc/haproxy/errors/503.http
        errorfile 504 /etc/haproxy/errors/504.http
        stats enable
        stats auth username:password
        stats uri /haproxyStats

frontend http-in
        bind *:80

        # Define hosts based on domain names
        acl host_test1 hdr(host) -i test1.domain.com
        acl host_test2 hdr(host) -i test2.domain.com

        ## figure out backend to use based on domainname
        use_backend test1 if host_test1
        use_backend test2 if host_test2


backend test1 # test1.domain.com container
    balance roundrobin
    option httpclose
    option forwardfor
    server s2 172.17.0.26:80 # This ip should be the ip of hello-world container

backend test2 # test2.domain.com container
    balance roundrobin
    option httpclose
    option forwardfor
    server s1 172.17.0.26:80 # This ip should be ip of wordpress container

$ # Run haproxy and map the host directory ~/haproxy-config to /haproxy-override of the container
$ # See the image README and Dockerfile for info about this override behaviour.
$ # HAProxy is exposed on port 80 because all requests to the public ip should
$ # go to the HAProxy container.
$ docker run -d -p 80:80 -v ~/haproxy-config:/haproxy-override dockerfile/haproxy

The HAProxy configuration could be automated possibly with the use of etcd to store information about services or use a similar method to Automated nginx reverse proxy for docker. 

No comments:

Post a Comment