├── apache@8001.service ├── apache@8002.service ├── confd-demo ├── etc │ └── confd │ │ ├── conf.d │ │ └── nginx.toml │ │ ├── reload_nginx.sh │ │ └── templates │ │ └── nginx.conf.tmpl ├── README.md └── Dockerfile ├── README.md ├── confdata.service ├── apache.service ├── nginx.service ├── confd.service └── LICENSE /apache@8001.service: -------------------------------------------------------------------------------- 1 | apache.service -------------------------------------------------------------------------------- /apache@8002.service: -------------------------------------------------------------------------------- 1 | apache.service -------------------------------------------------------------------------------- /confd-demo/etc/confd/conf.d/nginx.toml: -------------------------------------------------------------------------------- 1 | [template] 2 | src = "nginx.conf.tmpl" 3 | dest = "/etc/nginx/nginx.conf" 4 | keys = [ 5 | "/test", 6 | ] 7 | reload_cmd = "/bin/bash /etc/confd/reload_nginx.sh" 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CoreOS load balancing demo 2 | 3 | These files accompany this blog post which illustrates 4 | how to load balance web containers in CoreOS using confd 5 | and nginx. 6 | 7 | http://blog.dixo.net/2015/02/load-balancing-with-coreos/ 8 | 9 | Improvements are welcome, just make a pull request. 10 | 11 | -------------------------------------------------------------------------------- /confd-demo/README.md: -------------------------------------------------------------------------------- 1 | # confd-demo 2 | 3 | This container is a demonstration of how run confd in 4 | a separate container from nginx. If uses a shared 5 | data volume for the nginx config, with the confd container 6 | using the Docker API to send a HUP signal to the nginx 7 | container. 8 | 9 | See this blog post for the full details 10 | 11 | http://blog.dixo.net/2015/02/load-balancing-with-coreos/ 12 | 13 | Improvements are welcome, just make a pull request. -------------------------------------------------------------------------------- /confd-demo/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:14.04 2 | 3 | RUN apt-get update && \ 4 | DEBIAN_FRONTEND=noninteractive apt-get -y install curl && \ 5 | curl -o /usr/bin/confd -L https://github.com/kelseyhightower/confd/releases/download/v0.7.1/confd-0.7.1-linux-amd64 && \ 6 | chmod 755 /usr/bin/confd 7 | 8 | ADD etc/confd/ /etc/confd 9 | 10 | #this environemtn variable needs to be passed in 11 | CMD /usr/bin/confd -interval=60 -node=http://$COREOS_PRIVATE_IPV4:4001 12 | -------------------------------------------------------------------------------- /confdata.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Configuration Data Volume Service 3 | After=docker.service 4 | Requires=docker.service 5 | 6 | [Service] 7 | EnvironmentFile=/etc/environment 8 | 9 | #we aren't a normal service, we just need to ensure that a data volume 10 | #exists, and create one if it doesn't 11 | Type=oneshot 12 | RemainAfterExit=yes 13 | 14 | ExecStartPre=-/usr/bin/docker rm conf-data 15 | ExecStart=/usr/bin/docker run -v /etc/nginx --name conf-data nginx echo "created new data container" 16 | -------------------------------------------------------------------------------- /confd-demo/etc/confd/reload_nginx.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #this script is invoked by confd when it updates the templated 3 | #configuration files. We use the Docker API to tell the docker service 4 | #on the host to send a HUP signal to nginx. This requires that the 5 | #confd container has got the /var/run/docker.sock unix socket exposed to 6 | #it, which means launching the container with 7 | #-v /var/run/docker.sock:/var/run/docker.sock 8 | 9 | #so instead, we send an http request over the domain socket 10 | echo -e "POST /containers/nginx.service/kill?signal=HUP HTTP/1.0\r\n" | \ 11 | nc -U /var/run/docker.sock 12 | 13 | -------------------------------------------------------------------------------- /apache.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=hello world web service port %i 3 | After=docker.service 4 | Requires=docker.service 5 | 6 | [Service] 7 | EnvironmentFile=/etc/environment 8 | ExecStartPre=-/usr/bin/docker kill apache-%i 9 | ExecStartPre=-/usr/bin/docker rm apache-%i 10 | ExecStartPre=/usr/bin/docker pull tutum/hello-world 11 | ExecStartPre=/usr/bin/etcdctl set /test/apache-%i ${COREOS_PRIVATE_IPV4}:%i 12 | ExecStart=/usr/bin/docker run --rm --name apache-%i -p ${COREOS_PRIVATE_IPV4}:%i:80 tutum/hello-world 13 | ExecStop=/usr/bin/etcdctl rm /test/apache-%i 14 | ExecStop=/usr/bin/docker stop -t 3 apache-%i 15 | Restart=on-failure 16 | -------------------------------------------------------------------------------- /nginx.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Nginx Service 3 | After=confd.service 4 | 5 | #we won't want it to require the service - that would stop us restarting 6 | #it, which is safe 7 | #Requires=confd.service 8 | 9 | [Service] 10 | EnvironmentFile=/etc/environment 11 | ExecStartPre=-/usr/bin/docker kill %n 12 | ExecStartPre=-/usr/bin/docker rm %n 13 | ExecStartPre=/usr/bin/docker pull nginx 14 | ExecStart=/usr/bin/docker run --name %n -p 80:80 --volumes-from=conf-data nginx 15 | ExecStop=/usr/bin/docker stop -t 3 %n 16 | Restart=on-failure 17 | 18 | [X-Fleet] 19 | #we need to be on the same machine as confdata 20 | MachineOf=confdata.service -------------------------------------------------------------------------------- /confd.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Configuration Service 3 | 4 | #our data volume must be ready 5 | After=confdata.service 6 | Requires=confdata.service 7 | 8 | 9 | [Service] 10 | EnvironmentFile=/etc/environment 11 | 12 | 13 | #kill any existing confd 14 | ExecStartPre=-/usr/bin/docker kill %n 15 | ExecStartPre=-/usr/bin/docker rm %n 16 | 17 | #preload container...this ensures we fail if our registry is down and we can't 18 | #obtain the build we're expecting 19 | ExecStartPre=/usr/bin/docker pull lordelph/confd-demo 20 | 21 | #we need to provide our confd container with the IP it can reach etcd 22 | #on, the docker socket so it send HUP signals to nginx, and our data volume 23 | ExecStart=/usr/bin/docker run --rm \ 24 | -e COREOS_PRIVATE_IPV4=${COREOS_PRIVATE_IPV4} \ 25 | -v /var/run/docker.sock:/var/run/docker.sock \ 26 | --volumes-from=conf-data \ 27 | --name %n \ 28 | lordelph/confd-demo 29 | 30 | ExecStop=/usr/bin/docker stop -t 3 %n 31 | Restart=on-failure 32 | 33 | [X-Fleet] 34 | #we need to be on the same machine as confdata.service 35 | MachineOf=confdata.service -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Paul Dixon 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /confd-demo/etc/confd/templates/nginx.conf.tmpl: -------------------------------------------------------------------------------- 1 | user nginx; 2 | worker_processes 1; 3 | 4 | 5 | error_log /var/log/nginx/error.log warn; 6 | pid /var/run/nginx.pid; 7 | 8 | 9 | events { 10 | worker_connections 1024; 11 | } 12 | 13 | 14 | http { 15 | include /etc/nginx/mime.types; 16 | default_type application/octet-stream; 17 | 18 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 19 | '$status $body_bytes_sent "$http_referer" ' 20 | '"$http_user_agent" "$http_x_forwarded_for"'; 21 | 22 | access_log /var/log/nginx/access.log main; 23 | 24 | sendfile on; 25 | #tcp_nopush on; 26 | 27 | keepalive_timeout 65; 28 | 29 | #gzip on; 30 | 31 | upstream backend { 32 | {{range getvs "/test/*"}} 33 | server {{.}}; 34 | {{end}} 35 | } 36 | 37 | server { 38 | server_name myserver.example.com; 39 | 40 | location / { 41 | proxy_pass http://backend; 42 | proxy_redirect off; 43 | proxy_set_header Host $host; 44 | proxy_set_header X-Real-IP $remote_addr; 45 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 46 | 47 | add_header X-Handler $upstream_addr; 48 | } 49 | } 50 | 51 | 52 | include /etc/nginx/conf.d/*.conf; 53 | } 54 | --------------------------------------------------------------------------------