├── .gitignore
├── LICENSE
├── README.md
├── chapter-4
└── website
│ ├── .dockerignore
│ ├── .gitignore
│ ├── Dockerfile
│ ├── app.py
│ ├── docker-compose.yml
│ └── requirements.txt
├── chapter-5
└── website
│ ├── .dockerignore
│ ├── .gitignore
│ ├── Dockerfile
│ ├── Vagrantfile
│ ├── app.py
│ ├── docker-compose.yml
│ └── requirements.txt
├── chapter-6
├── deploy
│ └── units
│ │ ├── redis.service
│ │ └── rediscounter.service
└── website
│ ├── .dockerignore
│ ├── .gitignore
│ ├── Dockerfile
│ ├── Vagrantfile
│ ├── app.py
│ ├── docker-compose.yml
│ └── requirements.txt
├── chapter-7
├── deploy
│ ├── nginx
│ │ ├── Dockerfile
│ │ ├── certs
│ │ │ ├── dhparam.pem
│ │ │ ├── rediscounter.crt
│ │ │ └── rediscounter.key
│ │ ├── configs
│ │ │ ├── default.conf
│ │ │ └── nginx.conf
│ │ └── docker-entrypoint
│ └── units
│ │ ├── nginx.service
│ │ ├── redis.service
│ │ └── rediscounter.service
└── website
│ ├── .dockerignore
│ ├── .gitignore
│ ├── Dockerfile
│ ├── Vagrantfile
│ ├── app.py
│ ├── docker-compose.yml
│ └── requirements.txt
├── chapter-8
├── deploy
│ ├── git
│ │ └── post-receive
│ │ │ ├── nginx
│ │ │ └── rediscounter
│ ├── nginx
│ │ ├── Dockerfile
│ │ ├── certs
│ │ │ ├── dhparam.pem
│ │ │ ├── rediscounter.crt
│ │ │ └── rediscounter.key
│ │ ├── configs
│ │ │ ├── default.conf
│ │ │ └── nginx.conf
│ │ └── docker-entrypoint
│ └── units
│ │ ├── nginx.service
│ │ ├── redis.service
│ │ └── rediscounter.service
└── website
│ ├── .dockerignore
│ ├── .gitignore
│ ├── Dockerfile
│ ├── Vagrantfile
│ ├── app.py
│ ├── docker-compose.yml
│ └── requirements.txt
└── chapter-9
├── deploy
├── git
│ └── post-receive
│ │ ├── nginx
│ │ └── rediscounter
├── nginx
│ ├── Dockerfile
│ ├── certs
│ │ ├── dhparam.pem
│ │ ├── rediscounter.crt
│ │ └── rediscounter.key
│ ├── configs
│ │ ├── default.conf
│ │ └── nginx.conf
│ └── docker-entrypoint
├── production
│ └── rules-save
└── units
│ ├── nginx.service
│ ├── redis.service
│ └── rediscounter.service
└── website
├── .dockerignore
├── .gitignore
├── Dockerfile
├── Vagrantfile
├── app.py
├── docker-compose.yml
└── requirements.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | .vagrant/
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015 Nick Janetakis
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Deploy web apps with Docker
2 |
3 | This repository contains progress points based on where you are in [Deploy web
4 | apps with Docker](https://leanpub.com/deploy-web-apps-with-docker), a book for
5 | deploying web applications with Docker by [Nick
6 | Janetakis](http://nickjanetakis.com/).
7 |
8 | ## License
9 |
10 | MIT
11 |
12 | ## Buy the Book
13 |
14 | You can buy [Deploy web apps with
15 | Docker](https://leanpub.com/deploy-web-apps-with-docker) on LeanPub.
16 |
17 | Just as a fair warning I maintained this book for years but it's no longer
18 | being updated. This repo is up to ensure folks who have the book can access the
19 | material. An up to date list of courses I've created around building and
20 | deploying web apps can be found here .
21 |
--------------------------------------------------------------------------------
/chapter-4/website/.dockerignore:
--------------------------------------------------------------------------------
1 | .git
2 | tmp/*
3 | log/*
4 | .dockerignore
5 |
--------------------------------------------------------------------------------
/chapter-4/website/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 |
5 | # OS and editor files
6 | .DS_Store
7 | */**.DS_Store
8 | ._*
9 | .*.sw*
10 | *~
11 | .idea/
12 | .mr.developer.cfg
13 | .project
14 | .pydevproject
15 | *.tmproj
16 | *.tmproject
17 | tmtags
18 |
--------------------------------------------------------------------------------
/chapter-4/website/Dockerfile:
--------------------------------------------------------------------------------
1 | # Use the barebones version of Python 2.7.10.
2 | FROM python:2.7.10-slim
3 | MAINTAINER Nick Janetakis
4 |
5 | # Install any packages that must be installed.
6 | RUN apt-get update && apt-get install -qq -y build-essential --fix-missing --no-install-recommends
7 |
8 | # Set up the install path for this service.
9 | ENV INSTALL_PATH /rediscounter
10 | RUN mkdir -p $INSTALL_PATH
11 |
12 | # Update the workdir to be where our app is installed.
13 | WORKDIR $INSTALL_PATH
14 |
15 | # Ensure packages are cached and only get updated when necessary. If we didn’t do this step then every time we pushed an app change it would also re-run pip install, even if no packages changed.
16 | COPY requirements.txt requirements.txt
17 | RUN pip install -r requirements.txt
18 |
19 | # Copy the source from your workstation to the image at the WORKDIR path.
20 | COPY . .
21 |
22 | # Create a volume so that nginx can read from it.
23 | VOLUME ["$INSTALL_PATH/build/public"]
24 |
25 | # The default command to run if no command is specified.
26 | CMD python app.py
27 |
--------------------------------------------------------------------------------
/chapter-4/website/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask
2 | from redis import StrictRedis
3 |
4 | app = Flask(__name__)
5 | redis = StrictRedis(host='redis')
6 |
7 | @app.route('/')
8 | def hello_world():
9 | hits = redis.incr('hits')
10 | return 'You visited {0} times!'.format(hits)
11 |
12 | if __name__ == '__main__':
13 | app.run(host='0.0.0.0', port=8000, debug=True)
14 |
--------------------------------------------------------------------------------
/chapter-4/website/docker-compose.yml:
--------------------------------------------------------------------------------
1 | redis:
2 | image: redis:2.8.21
3 | ports:
4 | - 6379:6379
5 | volumes:
6 | - ~/.docker-volumes/rediscounter/redis/data:/var/lib/redis/data
7 |
8 | website:
9 | build: .
10 | links:
11 | - redis
12 | volumes:
13 | - .:/rediscounter
14 | ports:
15 | - 8000:8000
16 |
17 | cadvisor:
18 | image: google/cadvisor:latest
19 | volumes:
20 | - /:/rootfs:ro
21 | - /var/run:/var/run:rw
22 | - /sys:/sys:ro
23 | - /var/lib/docker/:/var/lib/docker:ro
24 | ports:
25 | - 8080:8080
26 |
--------------------------------------------------------------------------------
/chapter-4/website/requirements.txt:
--------------------------------------------------------------------------------
1 | Flask==0.10.1
2 | redis==2.10.3
3 |
--------------------------------------------------------------------------------
/chapter-5/website/.dockerignore:
--------------------------------------------------------------------------------
1 | .git
2 | tmp/*
3 | log/*
4 | .dockerignore
5 | .vagrant/
6 |
--------------------------------------------------------------------------------
/chapter-5/website/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 |
5 | # OS and editor files
6 | .DS_Store
7 | */**.DS_Store
8 | ._*
9 | .*.sw*
10 | *~
11 | .idea/
12 | .mr.developer.cfg
13 | .project
14 | .pydevproject
15 | *.tmproj
16 | *.tmproject
17 | tmtags
18 |
19 | .vagrant/
20 |
--------------------------------------------------------------------------------
/chapter-5/website/Dockerfile:
--------------------------------------------------------------------------------
1 | # Use the barebones version of Python 2.7.10.
2 | FROM python:2.7.10-slim
3 | MAINTAINER Nick Janetakis
4 |
5 | # Install any packages that must be installed.
6 | RUN apt-get update && apt-get install -qq -y build-essential --fix-missing --no-install-recommends
7 |
8 | # Set up the install path for this service.
9 | ENV INSTALL_PATH /rediscounter
10 | RUN mkdir -p $INSTALL_PATH
11 |
12 | # Update the workdir to be where our app is installed.
13 | WORKDIR $INSTALL_PATH
14 |
15 | # Ensure packages are cached and only get updated when necessary. If we didn’t do this step then every time we pushed an app change it would also re-run pip install, even if no packages changed.
16 | COPY requirements.txt requirements.txt
17 | RUN pip install -r requirements.txt
18 |
19 | # Copy the source from your workstation to the image at the WORKDIR path.
20 | COPY . .
21 |
22 | # Create a volume so that nginx can read from it.
23 | VOLUME ["$INSTALL_PATH/build/public"]
24 |
25 | # The default command to run if no command is specified.
26 | CMD python app.py
27 |
--------------------------------------------------------------------------------
/chapter-5/website/Vagrantfile:
--------------------------------------------------------------------------------
1 | Vagrant.require_version '>= 1.6.0'
2 |
3 | # Configuration settings for the Virtual Machine.
4 | $update_channel = 'beta'
5 | $image_version = 'current'
6 | $vm_memory = 1024
7 | $vm_cpus = 1
8 | $forwarded_ports = {
9 | '8000' => '8000'
10 | }
11 | $vm_host = 'core-01'
12 | $vm_ip = '172.17.8.101'
13 |
14 | Vagrant.configure('2') do |config|
15 | config.ssh.insert_key = false
16 | config.ssh.forward_agent = true
17 |
18 | config.vm.box = 'coreos-%s' % [$update_channel]
19 | if $image_version != 'current'
20 | config.vm.box_version = $image_version
21 | end
22 | config.vm.box_url = 'http://%s.release.core-os.net/amd64-usr/%s/coreos_production_vagrant.json' % [$update_channel, $image_version]
23 |
24 | ['vmware_fusion', 'vmware_workstation'].each do |vmware|
25 | config.vm.provider vmware do |v, override|
26 | override.vm.box_url = 'http://%s.release.core-os.net/amd64-usr/%s/coreos_production_vagrant_vmware_fusion.json' % [$update_channel, $image_version]
27 | end
28 | end
29 |
30 | config.vm.provider :virtualbox do |v|
31 | v.check_guest_additions = false
32 | v.functional_vboxsf = false
33 | end
34 |
35 | if Vagrant.has_plugin?('vagrant-vbguest') then
36 | config.vbguest.auto_update = false
37 | end
38 |
39 | config.vm.define vm_name = $vm_host do |config|
40 | config.vm.hostname = vm_name
41 |
42 | config.vm.network :private_network, ip: $vm_ip
43 |
44 | $forwarded_ports.each do |guest, host|
45 | config.vm.network 'forwarded_port', guest: guest, host: host, auto_correct: true
46 | end
47 |
48 | ['vmware_fusion', 'vmware_workstation'].each do |vmware|
49 | config.vm.provider vmware do |v|
50 | v.gui = false
51 | v.vmx['memsize'] = $vm_memory
52 | v.vmx['numvcpus'] = $vm_cpus
53 | end
54 | end
55 |
56 | config.vm.provider :virtualbox do |vb|
57 | vb.gui = false
58 | vb.memory = $vm_memory
59 | vb.cpus = $vm_cpus
60 | end
61 | end
62 | end
63 |
--------------------------------------------------------------------------------
/chapter-5/website/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask
2 | from redis import StrictRedis
3 |
4 | app = Flask(__name__)
5 | redis = StrictRedis(host='redis')
6 |
7 | @app.route('/')
8 | def hello_world():
9 | hits = redis.incr('hits')
10 | return 'You visited {0} times!'.format(hits)
11 |
12 | if __name__ == '__main__':
13 | app.run(host='0.0.0.0', port=8000, debug=True)
14 |
--------------------------------------------------------------------------------
/chapter-5/website/docker-compose.yml:
--------------------------------------------------------------------------------
1 | redis:
2 | image: redis:2.8.21
3 | ports:
4 | - 6379:6379
5 | volumes:
6 | - ~/.docker-volumes/rediscounter/redis/data:/var/lib/redis/data
7 |
8 | website:
9 | build: .
10 | links:
11 | - redis
12 | volumes:
13 | - .:/rediscounter
14 | ports:
15 | - 8000:8000
16 |
17 | cadvisor:
18 | image: google/cadvisor:latest
19 | volumes:
20 | - /:/rootfs:ro
21 | - /var/run:/var/run:rw
22 | - /sys:/sys:ro
23 | - /var/lib/docker/:/var/lib/docker:ro
24 | ports:
25 | - 8080:8080
26 |
--------------------------------------------------------------------------------
/chapter-5/website/requirements.txt:
--------------------------------------------------------------------------------
1 | Flask==0.10.1
2 | redis==2.10.3
3 |
--------------------------------------------------------------------------------
/chapter-6/deploy/units/redis.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Run %p
3 | Requires=docker.service
4 | After=docker.service
5 |
6 | [Service]
7 | Restart=always
8 | ExecStartPre=-/usr/bin/mkdir -p /var/lib/%p/data
9 | ExecStartPre=-/usr/bin/docker kill %p
10 | ExecStartPre=-/usr/bin/docker rm -f %p
11 | ExecStart=/usr/bin/docker run --rm --name %p \
12 | -v /var/lib/%p/data:/var/lib/%p/data -p 6379:6379 %p:2.8.21
13 | ExecStop=/usr/bin/docker stop %p
14 |
15 | [Install]
16 | WantedBy=multi-user.target rediscounter.service
17 |
--------------------------------------------------------------------------------
/chapter-6/deploy/units/rediscounter.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Run %p
3 | Requires=docker.service redis.service
4 | After=docker.service redis.service
5 |
6 | [Service]
7 | Restart=always
8 | ExecStartPre=-/usr/bin/docker kill %p
9 | ExecStartPre=-/usr/bin/docker rm -f %p
10 | ExecStart=/usr/bin/docker run -t --rm --name %p \
11 | --link redis:redis -p 8000:8000 %p
12 | ExecStop=/usr/bin/docker stop %p
13 |
14 | [Install]
15 | WantedBy=multi-user.target
16 |
--------------------------------------------------------------------------------
/chapter-6/website/.dockerignore:
--------------------------------------------------------------------------------
1 | .git
2 | tmp/*
3 | log/*
4 | .dockerignore
5 | .vagrant/
6 |
--------------------------------------------------------------------------------
/chapter-6/website/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 |
5 | # OS and editor files
6 | .DS_Store
7 | */**.DS_Store
8 | ._*
9 | .*.sw*
10 | *~
11 | .idea/
12 | .mr.developer.cfg
13 | .project
14 | .pydevproject
15 | *.tmproj
16 | *.tmproject
17 | tmtags
18 |
19 | .vagrant/
20 |
--------------------------------------------------------------------------------
/chapter-6/website/Dockerfile:
--------------------------------------------------------------------------------
1 | # Use the barebones version of Python 2.7.10.
2 | FROM python:2.7.10-slim
3 | MAINTAINER Nick Janetakis
4 |
5 | # Install any packages that must be installed.
6 | RUN apt-get update && apt-get install -qq -y build-essential --fix-missing --no-install-recommends
7 |
8 | # Set up the install path for this service.
9 | ENV INSTALL_PATH /rediscounter
10 | RUN mkdir -p $INSTALL_PATH
11 |
12 | # Update the workdir to be where our app is installed.
13 | WORKDIR $INSTALL_PATH
14 |
15 | # Ensure packages are cached and only get updated when necessary. If we didn’t do this step then every time we pushed an app change it would also re-run pip install, even if no packages changed.
16 | COPY requirements.txt requirements.txt
17 | RUN pip install -r requirements.txt
18 |
19 | # Copy the source from your workstation to the image at the WORKDIR path.
20 | COPY . .
21 |
22 | # Create a volume so that nginx can read from it.
23 | VOLUME ["$INSTALL_PATH/build/public"]
24 |
25 | # The default command to run if no command is specified.
26 | CMD python app.py
27 |
--------------------------------------------------------------------------------
/chapter-6/website/Vagrantfile:
--------------------------------------------------------------------------------
1 | Vagrant.require_version '>= 1.6.0'
2 |
3 | # Configuration settings for the Virtual Machine.
4 | $update_channel = 'beta'
5 | $image_version = 'current'
6 | $vm_memory = 1024
7 | $vm_cpus = 1
8 | $forwarded_ports = {
9 | '8000' => '8000'
10 | }
11 | $vm_host = 'core-01'
12 | $vm_ip = '172.17.8.101'
13 |
14 | Vagrant.configure('2') do |config|
15 | config.ssh.insert_key = false
16 | config.ssh.forward_agent = true
17 |
18 | config.vm.box = 'coreos-%s' % [$update_channel]
19 | if $image_version != 'current'
20 | config.vm.box_version = $image_version
21 | end
22 | config.vm.box_url = 'http://%s.release.core-os.net/amd64-usr/%s/coreos_production_vagrant.json' % [$update_channel, $image_version]
23 |
24 | ['vmware_fusion', 'vmware_workstation'].each do |vmware|
25 | config.vm.provider vmware do |v, override|
26 | override.vm.box_url = 'http://%s.release.core-os.net/amd64-usr/%s/coreos_production_vagrant_vmware_fusion.json' % [$update_channel, $image_version]
27 | end
28 | end
29 |
30 | config.vm.provider :virtualbox do |v|
31 | v.check_guest_additions = false
32 | v.functional_vboxsf = false
33 | end
34 |
35 | if Vagrant.has_plugin?('vagrant-vbguest') then
36 | config.vbguest.auto_update = false
37 | end
38 |
39 | config.vm.define vm_name = $vm_host do |config|
40 | config.vm.hostname = vm_name
41 |
42 | config.vm.network :private_network, ip: $vm_ip
43 |
44 | $forwarded_ports.each do |guest, host|
45 | config.vm.network 'forwarded_port', guest: guest, host: host, auto_correct: true
46 | end
47 |
48 | ['vmware_fusion', 'vmware_workstation'].each do |vmware|
49 | config.vm.provider vmware do |v|
50 | v.gui = false
51 | v.vmx['memsize'] = $vm_memory
52 | v.vmx['numvcpus'] = $vm_cpus
53 | end
54 | end
55 |
56 | config.vm.provider :virtualbox do |vb|
57 | vb.gui = false
58 | vb.memory = $vm_memory
59 | vb.cpus = $vm_cpus
60 | end
61 | end
62 | end
63 |
--------------------------------------------------------------------------------
/chapter-6/website/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask
2 | from redis import StrictRedis
3 |
4 | app = Flask(__name__)
5 | redis = StrictRedis(host='redis')
6 |
7 | @app.route('/')
8 | def hello_world():
9 | hits = redis.incr('hits')
10 | return 'You visited {0} times!'.format(hits)
11 |
12 | if __name__ == '__main__':
13 | app.run(host='0.0.0.0', port=8000, debug=True)
14 |
--------------------------------------------------------------------------------
/chapter-6/website/docker-compose.yml:
--------------------------------------------------------------------------------
1 | redis:
2 | image: redis:2.8.21
3 | ports:
4 | - 6379:6379
5 | volumes:
6 | - ~/.docker-volumes/rediscounter/redis/data:/var/lib/redis/data
7 |
8 | website:
9 | build: .
10 | links:
11 | - redis
12 | volumes:
13 | - .:/rediscounter
14 | ports:
15 | - 8000:8000
16 |
17 | cadvisor:
18 | image: google/cadvisor:latest
19 | volumes:
20 | - /:/rootfs:ro
21 | - /var/run:/var/run:rw
22 | - /sys:/sys:ro
23 | - /var/lib/docker/:/var/lib/docker:ro
24 | ports:
25 | - 8080:8080
26 |
--------------------------------------------------------------------------------
/chapter-6/website/requirements.txt:
--------------------------------------------------------------------------------
1 | Flask==0.10.1
2 | redis==2.10.3
3 |
--------------------------------------------------------------------------------
/chapter-7/deploy/nginx/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM nginx:1.9.3
2 | MAINTAINER Nick Janetakis
3 |
4 | # Delete default static pages.
5 | RUN rm /usr/share/nginx/html/*
6 |
7 | # Copy over the custom nginx and default configs.
8 | COPY configs/nginx.conf /etc/nginx/nginx.conf
9 | COPY configs/default.conf /etc/nginx/conf.d/default.conf
10 |
11 | # Copy over the self signed SSL certificates.
12 | COPY certs/rediscounter.crt /etc/ssl/certs/rediscounter.crt
13 | COPY certs/rediscounter.key /etc/ssl/private/rediscounter.key
14 | COPY certs/dhparam.pem /etc/ssl/private/dhparam.pem
15 |
16 | # Allow us to customize the entry point of the image.
17 | COPY docker-entrypoint /
18 | RUN chmod +x /docker-entrypoint
19 | ENTRYPOINT ["/docker-entrypoint"]
20 |
21 | # Start nginx in the foreground.
22 | CMD ["nginx", "-g", "daemon off;"]
--------------------------------------------------------------------------------
/chapter-7/deploy/nginx/certs/dhparam.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN DH PARAMETERS-----
2 | MIIBCAKCAQEA4ZvlxM3OiUA+WWjQolRqxLazGeM0sVwXUJLpPlVrjZH/9Slo7ovq
3 | VZhFgBTZToXZlO+rG77/7XvkLxOwa/Bxj9sEyieObFh5M3AYpqPliotsPDNvNl1l
4 | Ys09k+mYUqW/WToVHburvDAHLseHBiRPTkKMEgZ79wZE9SHiHXOJnNSb2HvgfnHz
5 | 4QM+e/z4Yx1q22TF+lACm/zIFrPhUQpu5RkF7R3jwurVdWa5XyVljGPlnQXbeBns
6 | fECKaU2wsQc2+t5gpkdxDlX7ZDQ9Nh+DkW0WCrGyLm2cBfP2qm5X4RL1ge3LZzYC
7 | CpHZ7NCtHFneOUtlZ+XMLxHbseosm2PNYwIBAg==
8 | -----END DH PARAMETERS-----
9 |
--------------------------------------------------------------------------------
/chapter-7/deploy/nginx/certs/rediscounter.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDhzCCAm+gAwIBAgIJAJFkaQ5PfmT8MA0GCSqGSIb3DQEBCwUAMFoxCzAJBgNV
3 | BAYTAlVTMRAwDgYDVQQIDAdOZXdZb3JrMRAwDgYDVQQHDAdOZXdZb3JrMQswCQYD
4 | VQQKDAJJVDEaMBgGA1UEAwwRbG9jYWxyZWdpc3RyeS5jb20wHhcNMTUwODAzMTQx
5 | MDAyWhcNMjUwNzMxMTQxMDAyWjBaMQswCQYDVQQGEwJVUzEQMA4GA1UECAwHTmV3
6 | WW9yazEQMA4GA1UEBwwHTmV3WW9yazELMAkGA1UECgwCSVQxGjAYBgNVBAMMEWxv
7 | Y2FscmVnaXN0cnkuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
8 | 3QgNGc1Dpf4SMls0R/RroX7d6cniisI2XgspVHHYW8hDx/NO8NdZf3KCD9T+SAVg
9 | 9DddbGx7StxhMnB1lW7HmeOzGFR4NjOuh4fz0iYYoLRd4gzkit0D+OSBsnr4tLle
10 | yysEC0wYkLAHCHeZlZ9u54DTW9bzGW4KNFAkLagBQMGcg2bkXpqOr1xrO+6uc5IV
11 | 8VM6yoedXlDek6K0rsxRUmh/8jcEXMwFTqmnTexShYVB+Ji5XLPgikSOmQje+3JF
12 | 1tE8rIsPhF98mWz/wRRBaV+5LJtTM54TXmi4BrmMALKM0Lo1khvWitwIfPOJWGEX
13 | VJllkJARv2KFX87vkEv6dQIDAQABo1AwTjAdBgNVHQ4EFgQUnUGjY1oLqT00U7y2
14 | iGOSgpx6EZkwHwYDVR0jBBgwFoAUnUGjY1oLqT00U7y2iGOSgpx6EZkwDAYDVR0T
15 | BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAeS06ifrHBKZ700o4bjEt2vFg1pcK
16 | abk8Bw7Vcn2RvDB09lJg3UFRs6CrJFqOnVF+AUA2goB8UKP7/LeYnN00DdZsLRi9
17 | sY93agdq95iv62+VdCnA+XleDS01wQFwzOlXb7p76y9a/v3SItMB9viXZ93wIo8E
18 | C0Owql0tvevvxqkxPru2QQO6JOzA70mQ19vQJsdBuviTeGMul7trZeOTmDRlR5vT
19 | u9h5Xk5bLV50H56MlZNOJvY+rnX+yk2Qgru2HDlOwb2vYYOZvSqiAHCuIB3VslpP
20 | iX0gAyV5WeSxmLQna6IxJIuNUUdq4UR6ZoACz69DQa1WO+dbs9jWseD5Cg==
21 | -----END CERTIFICATE-----
22 |
--------------------------------------------------------------------------------
/chapter-7/deploy/nginx/certs/rediscounter.key:
--------------------------------------------------------------------------------
1 | -----BEGIN PRIVATE KEY-----
2 | MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDdCA0ZzUOl/hIy
3 | WzRH9Guhft3pyeKKwjZeCylUcdhbyEPH807w11l/coIP1P5IBWD0N11sbHtK3GEy
4 | cHWVbseZ47MYVHg2M66Hh/PSJhigtF3iDOSK3QP45IGyevi0uV7LKwQLTBiQsAcI
5 | d5mVn27ngNNb1vMZbgo0UCQtqAFAwZyDZuRemo6vXGs77q5zkhXxUzrKh51eUN6T
6 | orSuzFFSaH/yNwRczAVOqadN7FKFhUH4mLlcs+CKRI6ZCN77ckXW0Tysiw+EX3yZ
7 | bP/BFEFpX7ksm1MznhNeaLgGuYwAsozQujWSG9aK3Ah884lYYRdUmWWQkBG/YoVf
8 | zu+QS/p1AgMBAAECggEBANG7sQq5rqZU5xlnV72rXXIZuyL7UX7PeN1WA/rAKEg3
9 | SLHz2wVHowH/OxEgz8SxbeVun7ShX4CSi5xcAAcy3i3VVX0RshvkgIjUZXUUdywO
10 | 2kMEbtyhigJjefpNG7AJcbyhba32oByzG4laS58hcRA1OtmbpoOL2hz3qsyz7bRt
11 | /vVaJHFTm6CSz9Wn/m2xWmyLJn3ObHE8AMp8FteztkcNceqGWpga99u6PSMFJ0G8
12 | JT/RDUUO2WA5hf0GmJbBTyqx6977ivFGeYhXrlpOxxVxkx0x+Gd7p/F/FNhGmr1l
13 | qIa+z+NcWOxKV30BG7Ra9A0doxVIojQCASLkPN3rXAECgYEA/QELsstfvSmdZvUJ
14 | 6Ox3g+Ozxxm5w0tiCEaeC0nlsrENPabSq9xEs2jbKhww5ox3sPs6OKusRD6YPE2t
15 | Eq/uEVyn+oGOr+J4Q4zQTDNrd2QAYGMZRNuZkTOFpe8KZBmTIo4mCtEGp2SUSJcC
16 | uL6cO6DbwSikrijHvkFu6YpMSQECgYEA36YVe9Uz0xLbmtxeYVSijeEfvfNRDjys
17 | cbjAI6eFmntR8XTmEWoZVRKmA9kDg9IlK82vZeEqMlEviagO6eAjl6rC9lxfBTUl
18 | BbQWaAFZGimQInk0cWiHc8AhdOK+H7LKaEMIycMNu2AUoWBN/Mc9CGy8DFrc3RRQ
19 | FuYrXWGpnXUCgYEAqpks6TfHa8cG0ujB8OSaRj2g+Mz4/J31EX2Ejjoa/53xPrQh
20 | dC9Hx+4ZclCmDJ+FCbqtbI8dzrqibm82F9a3Yc+nmPwJWcIMtAfcYLV/bnbo5hWM
21 | cWjeKRGjudrwl8TC+Nb/AeYmZXMlpbjl5erpcC+sXpfoS2NGJJz8i89sVwECgYBP
22 | ZYTG+390dYNkzMrsvsEeoUdFhfXGmh+WF8KOZdB2cUU79QYgNIxduUsanpYy3A26
23 | KUEVaAQ07MF1myYAPUQlecfQ8iYBkUZdaftyXNgnA45ZzrGheTxtCU5XUo+wbSaS
24 | MQoTpp1fYdKxH6FQFeNC9Gcl87PpAGcWWgwXEK7IaQKBgQDn7kAAlxOYNQye8320
25 | IfOoUyzFMLotlGclqKvkhLEDmg5aUEurdOAR01qSQt2OcJ5AlXJ2UJpsOCx7cXg2
26 | qt37wOz5F0L5jsHuPDLImQm2rdPuWZH2VwrYF71ejkmAw1sAOaPQCYpl8wGbKGRt
27 | y7ZDJzUMJ6e3JMLVYcOBIvRLGw==
28 | -----END PRIVATE KEY-----
29 |
--------------------------------------------------------------------------------
/chapter-7/deploy/nginx/configs/default.conf:
--------------------------------------------------------------------------------
1 | upstream rediscounter {
2 | # The Flask application.
3 | server rediscounter:8000;
4 | }
5 |
6 | # In case you want 'www' addresses to be automatically redirected without 'www'.
7 | # server {
8 | # listen 80;
9 | # listen 443;
10 | # server_name www.yourrealdomain.com;
11 | # return 301 https://yourrealdomain.com$request_uri;
12 | #}
13 |
14 | server {
15 | listen 80 default deferred;
16 | server_name 172.17.8.101;
17 |
18 | # All http traffic will get redirected to SSL.
19 | return 307 https://$host$request_uri;
20 | }
21 |
22 | server {
23 | # "deferred" reduces the number of formalities between the server and client.
24 | listen 443 default deferred;
25 | server_name 172.17.8.101;
26 |
27 | # Static asset path, which is read from the rediscounter's VOLUME. In this
28 | # case the example application has no assets, but this is how you would
29 | # configure assets to be served through nginx.
30 | root /rediscounter/build/public;
31 |
32 | # Ensure timeouts are equal across browsers and raise the max content-length size.
33 | keepalive_timeout 60;
34 | client_max_body_size 5m;
35 |
36 | # SSL goodness.
37 | ssl on;
38 | ssl_certificate /etc/ssl/certs/rediscounter.crt;
39 | ssl_certificate_key /etc/ssl/private/rediscounter.key;
40 | ssl_session_cache shared:SSL:50m;
41 | ssl_session_timeout 5m;
42 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
43 | ssl_prefer_server_ciphers on;
44 | ssl_ciphers "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA";
45 | ssl_dhparam /etc/ssl/private/dhparam.pem;
46 | ssl_ecdh_curve secp384r1;
47 | add_header Strict-Transport-Security 'max-age=63072000; includeSubDomains;' always;
48 |
49 | # Disallow access to hidden files and directories.
50 | location ~ /\. {
51 | return 404;
52 | access_log off;
53 | log_not_found off;
54 | }
55 |
56 | # Allow optionally writing an index.html file to take precedence over the upstream.
57 | try_files $uri $uri/index.html $uri.html @rediscounter;
58 |
59 | # Attempt to load the favicon or fall back to status code 204.
60 | location = /favicon.ico {
61 | try_files /favicon.ico = 204;
62 | access_log off;
63 | log_not_found off;
64 | }
65 |
66 | # Load the Flask app back end with proper headers.
67 | location @rediscounter {
68 | proxy_set_header X-Forwarded-Proto $scheme;
69 | proxy_set_header Host $http_host;
70 | proxy_set_header X-Real-IP $remote_addr;
71 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
72 | proxy_redirect off;
73 | proxy_pass http://rediscounter;
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/chapter-7/deploy/nginx/configs/nginx.conf:
--------------------------------------------------------------------------------
1 | # Number of workers to run, usually equals number of CPU cores.
2 | worker_processes auto;
3 |
4 | # Maximum number of opened files per process.
5 | worker_rlimit_nofile 4096;
6 |
7 | events {
8 | # Maximum number of simultaneous connections that can be opened by a worker process.
9 | worker_connections 1024;
10 | }
11 |
12 | http {
13 | include /etc/nginx/mime.types;
14 | default_type application/octet-stream;
15 |
16 | # ---------------------------------------------------------------------------
17 | # Security settings from:
18 | # https://gist.github.com/plentz/6737338
19 |
20 | # Disable nginx version from being displayed on errors.
21 | server_tokens off;
22 |
23 | # config to don't allow the browser to render the page inside an frame or iframe
24 | # and avoid clickjacking http://en.wikipedia.org/wiki/Clickjacking
25 | # if you need to allow [i]frames, you can use SAMEORIGIN or even set an uri with ALLOW-FROM uri
26 | # https://developer.mozilla.org/en-US/docs/HTTP/X-Frame-Options
27 | add_header X-Frame-Options SAMEORIGIN;
28 |
29 | # when serving user-supplied content, include a X-Content-Type-Options: nosniff header along with the Content-Type: header,
30 | # to disable content-type sniffing on some browsers.
31 | # https://www.owasp.org/index.php/List_of_useful_HTTP_headers
32 | # currently suppoorted in IE > 8 http://blogs.msdn.com/b/ie/archive/2008/09/02/ie8-security-part-vi-beta-2-update.aspx
33 | # http://msdn.microsoft.com/en-us/library/ie/gg622941(v=vs.85).aspx
34 | # 'soon' on Firefox https://bugzilla.mozilla.org/show_bug.cgi?id=471020
35 | add_header X-Content-Type-Options nosniff;
36 |
37 | # This header enables the Cross-site scripting (XSS) filter built into most recent web browsers.
38 | # It's usually enabled by default anyway, so the role of this header is to re-enable the filter for
39 | # this particular website if it was disabled by the user.
40 | # https://www.owasp.org/index.php/List_of_useful_HTTP_headers
41 | add_header X-XSS-Protection "1; mode=block";
42 | # ---------------------------------------------------------------------------
43 |
44 | # Avoid situations where a hostname is too long when dealing with vhosts.
45 | server_names_hash_bucket_size 64;
46 | server_names_hash_max_size 512;
47 |
48 | # Performance optimizations.
49 | sendfile on;
50 | tcp_nopush on;
51 |
52 | # http://nginx.org/en/docs/hash.html
53 | types_hash_max_size 2048;
54 |
55 | # Enable gzip for everything but IE6.
56 | gzip on;
57 | gzip_disable "msie6";
58 |
59 | # Default config for the app backend.
60 | include /etc/nginx/conf.d/default.conf;
61 | }
62 |
--------------------------------------------------------------------------------
/chapter-7/deploy/nginx/docker-entrypoint:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -e
3 |
4 | # Overwrite a few variables, this allows us to use the same template
5 | # for both development, staging and production.
6 | CONFIG_PATH="/etc/nginx/conf.d/default.conf"
7 | STAGING_IP="172.17.8.101"
8 | STAGING_HOSTNAME="core-01"
9 | DOMAIN_NAME="yourrealdomain.com"
10 |
11 | if [[ $(hostname) != "${STAGING_HOSTNAME}" ]]; then
12 | sed -i "s/${STAGING_IP}/${DOMAIN_NAME}/g" "${CONFIG_PATH}"
13 | fi
14 |
15 | # Execute the CMD from the Dockerfile.
16 | exec "$@"
17 |
--------------------------------------------------------------------------------
/chapter-7/deploy/units/nginx.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Run %p
3 | Requires=docker.service rediscounter.service
4 | After=docker.service rediscounter.service
5 |
6 | [Service]
7 | Restart=always
8 | ExecStartPre=-/usr/bin/docker kill %p
9 | ExecStartPre=-/usr/bin/docker rm -f %p
10 | ExecStart=/usr/bin/docker run -t --rm --name %p \
11 | -p 80:80 -p 443:443 \
12 | --link rediscounter:rediscounter \
13 | -v /etc/ssl/certs:/etc/ssl/certs \
14 | -v /etc/ssl/private:/etc/ssl/private %p
15 | ExecStop=/usr/bin/docker stop %p
16 |
17 | [Install]
18 | WantedBy=multi-user.target
19 |
--------------------------------------------------------------------------------
/chapter-7/deploy/units/redis.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Run %p
3 | Requires=docker.service
4 | After=docker.service
5 |
6 | [Service]
7 | Restart=always
8 | ExecStartPre=-/usr/bin/mkdir -p /var/lib/%p/data
9 | ExecStartPre=-/usr/bin/docker kill %p
10 | ExecStartPre=-/usr/bin/docker rm -f %p
11 | ExecStart=/usr/bin/docker run --rm --name %p \
12 | -v /var/lib/%p/data:/var/lib/%p/data -p 6379:6379 %p:2.8.21
13 | ExecStop=/usr/bin/docker stop %p
14 |
15 | [Install]
16 | WantedBy=multi-user.target rediscounter.service
17 |
--------------------------------------------------------------------------------
/chapter-7/deploy/units/rediscounter.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Run %p
3 | Requires=docker.service redis.service
4 | After=docker.service redis.service
5 |
6 | [Service]
7 | Restart=always
8 | ExecStartPre=-/usr/bin/docker kill %p
9 | ExecStartPre=-/usr/bin/docker rm -f %p
10 | ExecStart=/usr/bin/docker run -t --rm --name %p \
11 | --link redis:redis -p 8000:8000 %p
12 | ExecStartPost=-/usr/bin/docker stop nginx
13 | ExecStop=/usr/bin/docker stop %p
14 |
15 | [Install]
16 | WantedBy=multi-user.target nginx.service
17 |
--------------------------------------------------------------------------------
/chapter-7/website/.dockerignore:
--------------------------------------------------------------------------------
1 | .git
2 | tmp/*
3 | log/*
4 | .dockerignore
5 | .vagrant/
6 |
--------------------------------------------------------------------------------
/chapter-7/website/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 |
5 | # OS and editor files
6 | .DS_Store
7 | */**.DS_Store
8 | ._*
9 | .*.sw*
10 | *~
11 | .idea/
12 | .mr.developer.cfg
13 | .project
14 | .pydevproject
15 | *.tmproj
16 | *.tmproject
17 | tmtags
18 |
19 | .vagrant/
20 |
--------------------------------------------------------------------------------
/chapter-7/website/Dockerfile:
--------------------------------------------------------------------------------
1 | # Use the barebones version of Python 2.7.10.
2 | FROM python:2.7.10-slim
3 | MAINTAINER Nick Janetakis
4 |
5 | # Install any packages that must be installed.
6 | RUN apt-get update && apt-get install -qq -y build-essential --fix-missing --no-install-recommends
7 |
8 | # Set up the install path for this service.
9 | ENV INSTALL_PATH /rediscounter
10 | RUN mkdir -p $INSTALL_PATH
11 |
12 | # Update the workdir to be where our app is installed.
13 | WORKDIR $INSTALL_PATH
14 |
15 | # Ensure packages are cached and only get updated when necessary. If we didn’t do this step then every time we pushed an app change it would also re-run pip install, even if no packages changed.
16 | COPY requirements.txt requirements.txt
17 | RUN pip install -r requirements.txt
18 |
19 | # Copy the source from your workstation to the image at the WORKDIR path.
20 | COPY . .
21 |
22 | # Create a volume so that nginx can read from it.
23 | VOLUME ["$INSTALL_PATH/build/public"]
24 |
25 | # The default command to run if no command is specified.
26 | CMD python app.py
27 |
--------------------------------------------------------------------------------
/chapter-7/website/Vagrantfile:
--------------------------------------------------------------------------------
1 | Vagrant.require_version '>= 1.6.0'
2 |
3 | # Configuration settings for the Virtual Machine.
4 | $update_channel = 'beta'
5 | $image_version = 'current'
6 | $vm_memory = 1024
7 | $vm_cpus = 1
8 | $forwarded_ports = {
9 | '8000' => '8000'
10 | }
11 | $vm_host = 'core-01'
12 | $vm_ip = '172.17.8.101'
13 |
14 | Vagrant.configure('2') do |config|
15 | config.ssh.insert_key = false
16 | config.ssh.forward_agent = true
17 |
18 | config.vm.box = 'coreos-%s' % [$update_channel]
19 | if $image_version != 'current'
20 | config.vm.box_version = $image_version
21 | end
22 | config.vm.box_url = 'http://%s.release.core-os.net/amd64-usr/%s/coreos_production_vagrant.json' % [$update_channel, $image_version]
23 |
24 | ['vmware_fusion', 'vmware_workstation'].each do |vmware|
25 | config.vm.provider vmware do |v, override|
26 | override.vm.box_url = 'http://%s.release.core-os.net/amd64-usr/%s/coreos_production_vagrant_vmware_fusion.json' % [$update_channel, $image_version]
27 | end
28 | end
29 |
30 | config.vm.provider :virtualbox do |v|
31 | v.check_guest_additions = false
32 | v.functional_vboxsf = false
33 | end
34 |
35 | if Vagrant.has_plugin?('vagrant-vbguest') then
36 | config.vbguest.auto_update = false
37 | end
38 |
39 | config.vm.define vm_name = $vm_host do |config|
40 | config.vm.hostname = vm_name
41 |
42 | config.vm.network :private_network, ip: $vm_ip
43 |
44 | $forwarded_ports.each do |guest, host|
45 | config.vm.network 'forwarded_port', guest: guest, host: host, auto_correct: true
46 | end
47 |
48 | ['vmware_fusion', 'vmware_workstation'].each do |vmware|
49 | config.vm.provider vmware do |v|
50 | v.gui = false
51 | v.vmx['memsize'] = $vm_memory
52 | v.vmx['numvcpus'] = $vm_cpus
53 | end
54 | end
55 |
56 | config.vm.provider :virtualbox do |vb|
57 | vb.gui = false
58 | vb.memory = $vm_memory
59 | vb.cpus = $vm_cpus
60 | end
61 | end
62 | end
63 |
--------------------------------------------------------------------------------
/chapter-7/website/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask
2 | from redis import StrictRedis
3 |
4 | app = Flask(__name__)
5 | redis = StrictRedis(host='redis')
6 |
7 | @app.route('/')
8 | def hello_world():
9 | hits = redis.incr('hits')
10 | return 'You visited {0} times!'.format(hits)
11 |
12 | if __name__ == '__main__':
13 | app.run(host='0.0.0.0', port=8000, debug=True)
14 |
--------------------------------------------------------------------------------
/chapter-7/website/docker-compose.yml:
--------------------------------------------------------------------------------
1 | redis:
2 | image: redis:2.8.21
3 | ports:
4 | - 6379:6379
5 | volumes:
6 | - ~/.docker-volumes/rediscounter/redis/data:/var/lib/redis/data
7 |
8 | website:
9 | build: .
10 | links:
11 | - redis
12 | volumes:
13 | - .:/rediscounter
14 | ports:
15 | - 8000:8000
16 |
17 | cadvisor:
18 | image: google/cadvisor:latest
19 | volumes:
20 | - /:/rootfs:ro
21 | - /var/run:/var/run:rw
22 | - /sys:/sys:ro
23 | - /var/lib/docker/:/var/lib/docker:ro
24 | ports:
25 | - 8080:8080
26 |
--------------------------------------------------------------------------------
/chapter-7/website/requirements.txt:
--------------------------------------------------------------------------------
1 | Flask==0.10.1
2 | redis==2.10.3
3 |
--------------------------------------------------------------------------------
/chapter-8/deploy/git/post-receive/nginx:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Configuration.
4 | REPO_NAME="nginx"
5 |
6 | # Check out the newest version of the code.
7 | export GIT_WORK_TREE="/var/git/${REPO_NAME}"
8 | git checkout -f
9 |
10 | TAG="$(git log --pretty=format:'%h' -n 1)"
11 | FULL_COMMIT_TAG="${REPO_NAME}:${TAG}"
12 | FULL_LATEST_TAG="${REPO_NAME}:latest"
13 |
14 | # Build the image with the proper commit tag.
15 | docker build -t "${FULL_COMMIT_TAG}" "${GIT_WORK_TREE}"
16 |
17 | # Get the Docker ID of the last built image.
18 | DOCKER_ID="$(docker images -q $REPO_NAME | head -1)"
19 |
20 | # Tag a latest version based off the proper commit tag.
21 | docker tag -f "${DOCKER_ID}" "${FULL_LATEST_TAG}"
22 |
23 | echo "Restarting ${REPO_NAME}"
24 | docker stop "${REPO_NAME}"
25 |
26 | echo "Removing untagged Docker images (may take a while)"
27 | docker rmi $(docker images --quiet --filter "dangling=true")
28 |
--------------------------------------------------------------------------------
/chapter-8/deploy/git/post-receive/rediscounter:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Configuration.
4 | REPO_NAME="rediscounter"
5 |
6 | # Check out the newest version of the code.
7 | export GIT_WORK_TREE="/var/git/${REPO_NAME}"
8 | git checkout -f
9 |
10 | TAG="$(git log --pretty=format:'%h' -n 1)"
11 | FULL_COMMIT_TAG="${REPO_NAME}:${TAG}"
12 | FULL_LATEST_TAG="${REPO_NAME}:latest"
13 |
14 | # Build the image with the proper commit tag.
15 | docker build -t "${FULL_COMMIT_TAG}" "${GIT_WORK_TREE}"
16 |
17 | # Get the Docker ID of the last built image.
18 | DOCKER_ID="$(docker images -q $REPO_NAME | head -1)"
19 |
20 | # Tag a latest version based off the proper commit tag.
21 | docker tag -f "${DOCKER_ID}" "${FULL_LATEST_TAG}"
22 |
23 | echo "Restarting ${REPO_NAME}"
24 | docker stop "${REPO_NAME}"
25 |
26 | echo "Removing untagged Docker images (may take a while)"
27 | docker rmi $(docker images --quiet --filter "dangling=true")
28 |
29 | echo "Restarting nginx"
30 | docker stop "nginx"
31 |
--------------------------------------------------------------------------------
/chapter-8/deploy/nginx/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM nginx:1.9.3
2 | MAINTAINER Nick Janetakis
3 |
4 | # Delete default static pages.
5 | RUN rm /usr/share/nginx/html/*
6 |
7 | # Copy over the custom nginx and default configs.
8 | COPY configs/nginx.conf /etc/nginx/nginx.conf
9 | COPY configs/default.conf /etc/nginx/conf.d/default.conf
10 |
11 | # Copy over the self signed SSL certificates.
12 | COPY certs/rediscounter.crt /etc/ssl/certs/rediscounter.crt
13 | COPY certs/rediscounter.key /etc/ssl/private/rediscounter.key
14 | COPY certs/dhparam.pem /etc/ssl/private/dhparam.pem
15 |
16 | # Allow us to customize the entry point of the image.
17 | COPY docker-entrypoint /
18 | RUN chmod +x /docker-entrypoint
19 | ENTRYPOINT ["/docker-entrypoint"]
20 |
21 | # Start nginx in the foreground.
22 | CMD ["nginx", "-g", "daemon off;"]
--------------------------------------------------------------------------------
/chapter-8/deploy/nginx/certs/dhparam.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN DH PARAMETERS-----
2 | MIIBCAKCAQEA4ZvlxM3OiUA+WWjQolRqxLazGeM0sVwXUJLpPlVrjZH/9Slo7ovq
3 | VZhFgBTZToXZlO+rG77/7XvkLxOwa/Bxj9sEyieObFh5M3AYpqPliotsPDNvNl1l
4 | Ys09k+mYUqW/WToVHburvDAHLseHBiRPTkKMEgZ79wZE9SHiHXOJnNSb2HvgfnHz
5 | 4QM+e/z4Yx1q22TF+lACm/zIFrPhUQpu5RkF7R3jwurVdWa5XyVljGPlnQXbeBns
6 | fECKaU2wsQc2+t5gpkdxDlX7ZDQ9Nh+DkW0WCrGyLm2cBfP2qm5X4RL1ge3LZzYC
7 | CpHZ7NCtHFneOUtlZ+XMLxHbseosm2PNYwIBAg==
8 | -----END DH PARAMETERS-----
9 |
--------------------------------------------------------------------------------
/chapter-8/deploy/nginx/certs/rediscounter.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDhzCCAm+gAwIBAgIJAJFkaQ5PfmT8MA0GCSqGSIb3DQEBCwUAMFoxCzAJBgNV
3 | BAYTAlVTMRAwDgYDVQQIDAdOZXdZb3JrMRAwDgYDVQQHDAdOZXdZb3JrMQswCQYD
4 | VQQKDAJJVDEaMBgGA1UEAwwRbG9jYWxyZWdpc3RyeS5jb20wHhcNMTUwODAzMTQx
5 | MDAyWhcNMjUwNzMxMTQxMDAyWjBaMQswCQYDVQQGEwJVUzEQMA4GA1UECAwHTmV3
6 | WW9yazEQMA4GA1UEBwwHTmV3WW9yazELMAkGA1UECgwCSVQxGjAYBgNVBAMMEWxv
7 | Y2FscmVnaXN0cnkuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
8 | 3QgNGc1Dpf4SMls0R/RroX7d6cniisI2XgspVHHYW8hDx/NO8NdZf3KCD9T+SAVg
9 | 9DddbGx7StxhMnB1lW7HmeOzGFR4NjOuh4fz0iYYoLRd4gzkit0D+OSBsnr4tLle
10 | yysEC0wYkLAHCHeZlZ9u54DTW9bzGW4KNFAkLagBQMGcg2bkXpqOr1xrO+6uc5IV
11 | 8VM6yoedXlDek6K0rsxRUmh/8jcEXMwFTqmnTexShYVB+Ji5XLPgikSOmQje+3JF
12 | 1tE8rIsPhF98mWz/wRRBaV+5LJtTM54TXmi4BrmMALKM0Lo1khvWitwIfPOJWGEX
13 | VJllkJARv2KFX87vkEv6dQIDAQABo1AwTjAdBgNVHQ4EFgQUnUGjY1oLqT00U7y2
14 | iGOSgpx6EZkwHwYDVR0jBBgwFoAUnUGjY1oLqT00U7y2iGOSgpx6EZkwDAYDVR0T
15 | BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAeS06ifrHBKZ700o4bjEt2vFg1pcK
16 | abk8Bw7Vcn2RvDB09lJg3UFRs6CrJFqOnVF+AUA2goB8UKP7/LeYnN00DdZsLRi9
17 | sY93agdq95iv62+VdCnA+XleDS01wQFwzOlXb7p76y9a/v3SItMB9viXZ93wIo8E
18 | C0Owql0tvevvxqkxPru2QQO6JOzA70mQ19vQJsdBuviTeGMul7trZeOTmDRlR5vT
19 | u9h5Xk5bLV50H56MlZNOJvY+rnX+yk2Qgru2HDlOwb2vYYOZvSqiAHCuIB3VslpP
20 | iX0gAyV5WeSxmLQna6IxJIuNUUdq4UR6ZoACz69DQa1WO+dbs9jWseD5Cg==
21 | -----END CERTIFICATE-----
22 |
--------------------------------------------------------------------------------
/chapter-8/deploy/nginx/certs/rediscounter.key:
--------------------------------------------------------------------------------
1 | -----BEGIN PRIVATE KEY-----
2 | MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDdCA0ZzUOl/hIy
3 | WzRH9Guhft3pyeKKwjZeCylUcdhbyEPH807w11l/coIP1P5IBWD0N11sbHtK3GEy
4 | cHWVbseZ47MYVHg2M66Hh/PSJhigtF3iDOSK3QP45IGyevi0uV7LKwQLTBiQsAcI
5 | d5mVn27ngNNb1vMZbgo0UCQtqAFAwZyDZuRemo6vXGs77q5zkhXxUzrKh51eUN6T
6 | orSuzFFSaH/yNwRczAVOqadN7FKFhUH4mLlcs+CKRI6ZCN77ckXW0Tysiw+EX3yZ
7 | bP/BFEFpX7ksm1MznhNeaLgGuYwAsozQujWSG9aK3Ah884lYYRdUmWWQkBG/YoVf
8 | zu+QS/p1AgMBAAECggEBANG7sQq5rqZU5xlnV72rXXIZuyL7UX7PeN1WA/rAKEg3
9 | SLHz2wVHowH/OxEgz8SxbeVun7ShX4CSi5xcAAcy3i3VVX0RshvkgIjUZXUUdywO
10 | 2kMEbtyhigJjefpNG7AJcbyhba32oByzG4laS58hcRA1OtmbpoOL2hz3qsyz7bRt
11 | /vVaJHFTm6CSz9Wn/m2xWmyLJn3ObHE8AMp8FteztkcNceqGWpga99u6PSMFJ0G8
12 | JT/RDUUO2WA5hf0GmJbBTyqx6977ivFGeYhXrlpOxxVxkx0x+Gd7p/F/FNhGmr1l
13 | qIa+z+NcWOxKV30BG7Ra9A0doxVIojQCASLkPN3rXAECgYEA/QELsstfvSmdZvUJ
14 | 6Ox3g+Ozxxm5w0tiCEaeC0nlsrENPabSq9xEs2jbKhww5ox3sPs6OKusRD6YPE2t
15 | Eq/uEVyn+oGOr+J4Q4zQTDNrd2QAYGMZRNuZkTOFpe8KZBmTIo4mCtEGp2SUSJcC
16 | uL6cO6DbwSikrijHvkFu6YpMSQECgYEA36YVe9Uz0xLbmtxeYVSijeEfvfNRDjys
17 | cbjAI6eFmntR8XTmEWoZVRKmA9kDg9IlK82vZeEqMlEviagO6eAjl6rC9lxfBTUl
18 | BbQWaAFZGimQInk0cWiHc8AhdOK+H7LKaEMIycMNu2AUoWBN/Mc9CGy8DFrc3RRQ
19 | FuYrXWGpnXUCgYEAqpks6TfHa8cG0ujB8OSaRj2g+Mz4/J31EX2Ejjoa/53xPrQh
20 | dC9Hx+4ZclCmDJ+FCbqtbI8dzrqibm82F9a3Yc+nmPwJWcIMtAfcYLV/bnbo5hWM
21 | cWjeKRGjudrwl8TC+Nb/AeYmZXMlpbjl5erpcC+sXpfoS2NGJJz8i89sVwECgYBP
22 | ZYTG+390dYNkzMrsvsEeoUdFhfXGmh+WF8KOZdB2cUU79QYgNIxduUsanpYy3A26
23 | KUEVaAQ07MF1myYAPUQlecfQ8iYBkUZdaftyXNgnA45ZzrGheTxtCU5XUo+wbSaS
24 | MQoTpp1fYdKxH6FQFeNC9Gcl87PpAGcWWgwXEK7IaQKBgQDn7kAAlxOYNQye8320
25 | IfOoUyzFMLotlGclqKvkhLEDmg5aUEurdOAR01qSQt2OcJ5AlXJ2UJpsOCx7cXg2
26 | qt37wOz5F0L5jsHuPDLImQm2rdPuWZH2VwrYF71ejkmAw1sAOaPQCYpl8wGbKGRt
27 | y7ZDJzUMJ6e3JMLVYcOBIvRLGw==
28 | -----END PRIVATE KEY-----
29 |
--------------------------------------------------------------------------------
/chapter-8/deploy/nginx/configs/default.conf:
--------------------------------------------------------------------------------
1 | upstream rediscounter {
2 | # The Flask application.
3 | server rediscounter:8000;
4 | }
5 |
6 | # In case you want 'www' addresses to be automatically redirected without 'www'.
7 | # server {
8 | # listen 80;
9 | # listen 443;
10 | # server_name www.yourrealdomain.com;
11 | # return 301 https://yourrealdomain.com$request_uri;
12 | #}
13 |
14 | server {
15 | listen 80 default deferred;
16 | server_name 172.17.8.101;
17 |
18 | # All http traffic will get redirected to SSL.
19 | return 307 https://$host$request_uri;
20 | }
21 |
22 | server {
23 | # "deferred" reduces the number of formalities between the server and client.
24 | listen 443 default deferred;
25 | server_name 172.17.8.101;
26 |
27 | # Static asset path, which is read from the rediscounter's VOLUME. In this
28 | # case the example application has no assets, but this is how you would
29 | # configure assets to be served through nginx.
30 | root /rediscounter/build/public;
31 |
32 | # Ensure timeouts are equal across browsers and raise the max content-length size.
33 | keepalive_timeout 60;
34 | client_max_body_size 5m;
35 |
36 | # SSL goodness.
37 | ssl on;
38 | ssl_certificate /etc/ssl/certs/rediscounter.crt;
39 | ssl_certificate_key /etc/ssl/private/rediscounter.key;
40 | ssl_session_cache shared:SSL:50m;
41 | ssl_session_timeout 5m;
42 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
43 | ssl_prefer_server_ciphers on;
44 | ssl_ciphers "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA";
45 | ssl_dhparam /etc/ssl/private/dhparam.pem;
46 | ssl_ecdh_curve secp384r1;
47 | add_header Strict-Transport-Security 'max-age=63072000; includeSubDomains;' always;
48 |
49 | # Disallow access to hidden files and directories.
50 | location ~ /\. {
51 | return 404;
52 | access_log off;
53 | log_not_found off;
54 | }
55 |
56 | # Allow optionally writing an index.html file to take precedence over the upstream.
57 | try_files $uri $uri/index.html $uri.html @rediscounter;
58 |
59 | # Attempt to load the favicon or fall back to status code 204.
60 | location = /favicon.ico {
61 | try_files /favicon.ico = 204;
62 | access_log off;
63 | log_not_found off;
64 | }
65 |
66 | # Load the Flask app back end with proper headers.
67 | location @rediscounter {
68 | proxy_set_header X-Forwarded-Proto $scheme;
69 | proxy_set_header Host $http_host;
70 | proxy_set_header X-Real-IP $remote_addr;
71 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
72 | proxy_redirect off;
73 | proxy_pass http://rediscounter;
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/chapter-8/deploy/nginx/configs/nginx.conf:
--------------------------------------------------------------------------------
1 | # Number of workers to run, usually equals number of CPU cores.
2 | worker_processes auto;
3 |
4 | # Maximum number of opened files per process.
5 | worker_rlimit_nofile 4096;
6 |
7 | events {
8 | # Maximum number of simultaneous connections that can be opened by a worker process.
9 | worker_connections 1024;
10 | }
11 |
12 | http {
13 | include /etc/nginx/mime.types;
14 | default_type application/octet-stream;
15 |
16 | # ---------------------------------------------------------------------------
17 | # Security settings from:
18 | # https://gist.github.com/plentz/6737338
19 |
20 | # Disable nginx version from being displayed on errors.
21 | server_tokens off;
22 |
23 | # config to don't allow the browser to render the page inside an frame or iframe
24 | # and avoid clickjacking http://en.wikipedia.org/wiki/Clickjacking
25 | # if you need to allow [i]frames, you can use SAMEORIGIN or even set an uri with ALLOW-FROM uri
26 | # https://developer.mozilla.org/en-US/docs/HTTP/X-Frame-Options
27 | add_header X-Frame-Options SAMEORIGIN;
28 |
29 | # when serving user-supplied content, include a X-Content-Type-Options: nosniff header along with the Content-Type: header,
30 | # to disable content-type sniffing on some browsers.
31 | # https://www.owasp.org/index.php/List_of_useful_HTTP_headers
32 | # currently suppoorted in IE > 8 http://blogs.msdn.com/b/ie/archive/2008/09/02/ie8-security-part-vi-beta-2-update.aspx
33 | # http://msdn.microsoft.com/en-us/library/ie/gg622941(v=vs.85).aspx
34 | # 'soon' on Firefox https://bugzilla.mozilla.org/show_bug.cgi?id=471020
35 | add_header X-Content-Type-Options nosniff;
36 |
37 | # This header enables the Cross-site scripting (XSS) filter built into most recent web browsers.
38 | # It's usually enabled by default anyway, so the role of this header is to re-enable the filter for
39 | # this particular website if it was disabled by the user.
40 | # https://www.owasp.org/index.php/List_of_useful_HTTP_headers
41 | add_header X-XSS-Protection "1; mode=block";
42 | # ---------------------------------------------------------------------------
43 |
44 | # Avoid situations where a hostname is too long when dealing with vhosts.
45 | server_names_hash_bucket_size 64;
46 | server_names_hash_max_size 512;
47 |
48 | # Performance optimizations.
49 | sendfile on;
50 | tcp_nopush on;
51 |
52 | # http://nginx.org/en/docs/hash.html
53 | types_hash_max_size 2048;
54 |
55 | # Enable gzip for everything but IE6.
56 | gzip on;
57 | gzip_disable "msie6";
58 |
59 | # Default config for the app backend.
60 | include /etc/nginx/conf.d/default.conf;
61 | }
62 |
--------------------------------------------------------------------------------
/chapter-8/deploy/nginx/docker-entrypoint:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -e
3 |
4 | # Overwrite a few variables, this allows us to use the same template
5 | # for both development, staging and production.
6 | CONFIG_PATH="/etc/nginx/conf.d/default.conf"
7 | STAGING_IP="172.17.8.101"
8 | STAGING_HOSTNAME="core-01"
9 | DOMAIN_NAME="yourrealdomain.com"
10 |
11 | if [[ $(hostname) != "${STAGING_HOSTNAME}" ]]; then
12 | sed -i "s/${STAGING_IP}/${DOMAIN_NAME}/g" "${CONFIG_PATH}"
13 | fi
14 |
15 | # Execute the CMD from the Dockerfile.
16 | exec "$@"
17 |
--------------------------------------------------------------------------------
/chapter-8/deploy/units/nginx.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Run %p
3 | Requires=docker.service rediscounter.service
4 | After=docker.service rediscounter.service
5 |
6 | [Service]
7 | Restart=always
8 | ExecStartPre=-/usr/bin/docker kill %p
9 | ExecStartPre=-/usr/bin/docker rm -f %p
10 | ExecStart=/usr/bin/docker run -t --rm --name %p \
11 | -p 80:80 -p 443:443 \
12 | --link rediscounter:rediscounter \
13 | -v /etc/ssl/certs:/etc/ssl/certs \
14 | -v /etc/ssl/private:/etc/ssl/private %p
15 | ExecStop=/usr/bin/docker stop %p
16 |
17 | [Install]
18 | WantedBy=multi-user.target
19 |
--------------------------------------------------------------------------------
/chapter-8/deploy/units/redis.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Run %p
3 | Requires=docker.service
4 | After=docker.service
5 |
6 | [Service]
7 | Restart=always
8 | ExecStartPre=-/usr/bin/mkdir -p /var/lib/%p/data
9 | ExecStartPre=-/usr/bin/docker kill %p
10 | ExecStartPre=-/usr/bin/docker rm -f %p
11 | ExecStart=/usr/bin/docker run --rm --name %p \
12 | -v /var/lib/%p/data:/var/lib/%p/data -p 6379:6379 %p:2.8.21
13 | ExecStop=/usr/bin/docker stop %p
14 |
15 | [Install]
16 | WantedBy=multi-user.target rediscounter.service
17 |
--------------------------------------------------------------------------------
/chapter-8/deploy/units/rediscounter.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Run %p
3 | Requires=docker.service redis.service
4 | After=docker.service redis.service
5 |
6 | [Service]
7 | Restart=always
8 | ExecStartPre=-/usr/bin/docker kill %p
9 | ExecStartPre=-/usr/bin/docker rm -f %p
10 | ExecStart=/usr/bin/docker run -t --rm --name %p \
11 | --link redis:redis -p 8000:8000 %p
12 | ExecStartPost=-/usr/bin/docker stop nginx
13 | ExecStop=/usr/bin/docker stop %p
14 |
15 | [Install]
16 | WantedBy=multi-user.target nginx.service
17 |
--------------------------------------------------------------------------------
/chapter-8/website/.dockerignore:
--------------------------------------------------------------------------------
1 | .git
2 | tmp/*
3 | log/*
4 | .dockerignore
5 | .vagrant/
6 |
--------------------------------------------------------------------------------
/chapter-8/website/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 |
5 | # OS and editor files
6 | .DS_Store
7 | */**.DS_Store
8 | ._*
9 | .*.sw*
10 | *~
11 | .idea/
12 | .mr.developer.cfg
13 | .project
14 | .pydevproject
15 | *.tmproj
16 | *.tmproject
17 | tmtags
18 |
19 | .vagrant/
20 |
--------------------------------------------------------------------------------
/chapter-8/website/Dockerfile:
--------------------------------------------------------------------------------
1 | # Use the barebones version of Python 2.7.10.
2 | FROM python:2.7.10-slim
3 | MAINTAINER Nick Janetakis
4 |
5 | # Install any packages that must be installed.
6 | RUN apt-get update && apt-get install -qq -y build-essential --fix-missing --no-install-recommends
7 |
8 | # Set up the install path for this service.
9 | ENV INSTALL_PATH /rediscounter
10 | RUN mkdir -p $INSTALL_PATH
11 |
12 | # Update the workdir to be where our app is installed.
13 | WORKDIR $INSTALL_PATH
14 |
15 | # Ensure packages are cached and only get updated when necessary. If we didn’t do this step then every time we pushed an app change it would also re-run pip install, even if no packages changed.
16 | COPY requirements.txt requirements.txt
17 | RUN pip install -r requirements.txt
18 |
19 | # Copy the source from your workstation to the image at the WORKDIR path.
20 | COPY . .
21 |
22 | # Create a volume so that nginx can read from it.
23 | VOLUME ["$INSTALL_PATH/build/public"]
24 |
25 | # The default command to run if no command is specified.
26 | CMD python app.py
27 |
--------------------------------------------------------------------------------
/chapter-8/website/Vagrantfile:
--------------------------------------------------------------------------------
1 | Vagrant.require_version '>= 1.6.0'
2 |
3 | # Configuration settings for the Virtual Machine.
4 | $update_channel = 'beta'
5 | $image_version = 'current'
6 | $vm_memory = 1024
7 | $vm_cpus = 1
8 | $forwarded_ports = {
9 | '80' => '8080',
10 | '443' => '8081'
11 | }
12 | $vm_host = 'core-01'
13 | $vm_ip = '172.17.8.101'
14 |
15 | Vagrant.configure('2') do |config|
16 | config.ssh.insert_key = false
17 | config.ssh.forward_agent = true
18 |
19 | config.vm.box = 'coreos-%s' % [$update_channel]
20 | if $image_version != 'current'
21 | config.vm.box_version = $image_version
22 | end
23 | config.vm.box_url = 'http://%s.release.core-os.net/amd64-usr/%s/coreos_production_vagrant.json' % [$update_channel, $image_version]
24 |
25 | ['vmware_fusion', 'vmware_workstation'].each do |vmware|
26 | config.vm.provider vmware do |v, override|
27 | override.vm.box_url = 'http://%s.release.core-os.net/amd64-usr/%s/coreos_production_vagrant_vmware_fusion.json' % [$update_channel, $image_version]
28 | end
29 | end
30 |
31 | config.vm.provider :virtualbox do |v|
32 | v.check_guest_additions = false
33 | v.functional_vboxsf = false
34 | end
35 |
36 | if Vagrant.has_plugin?('vagrant-vbguest') then
37 | config.vbguest.auto_update = false
38 | end
39 |
40 | config.vm.define vm_name = $vm_host do |config|
41 | config.vm.hostname = vm_name
42 |
43 | config.vm.network :private_network, ip: $vm_ip
44 |
45 | $forwarded_ports.each do |guest, host|
46 | config.vm.network 'forwarded_port', guest: guest, host: host, auto_correct: true
47 | end
48 |
49 | ['vmware_fusion', 'vmware_workstation'].each do |vmware|
50 | config.vm.provider vmware do |v|
51 | v.gui = false
52 | v.vmx['memsize'] = $vm_memory
53 | v.vmx['numvcpus'] = $vm_cpus
54 | end
55 | end
56 |
57 | config.vm.provider :virtualbox do |vb|
58 | vb.gui = false
59 | vb.memory = $vm_memory
60 | vb.cpus = $vm_cpus
61 | end
62 |
63 | # Create bare git repos.
64 | config.vm.provision 'shell',
65 | inline: 'sudo mkdir -p /var/git/nginx.git /var/git/nginx /var/git/rediscounter.git /var/git/rediscounter'
66 |
67 | config.vm.provision 'shell',
68 | inline: 'sudo su && cd /var/git/nginx.git && git --bare init && chown -R core:core /var/git/nginx.git && chown -R core:core /var/git/nginx'
69 |
70 | config.vm.provision 'shell',
71 | inline: 'sudo su && cd /var/git/rediscounter.git && git --bare init && chown -R core:core /var/git/rediscounter.git && chown -R core:core /var/git/rediscounter'
72 |
73 |
74 | # Copy files into the VM instance upon provision.
75 | config.vm.provision 'file', source: '../deploy/nginx/certs',
76 | destination: '/tmp'
77 |
78 | config.vm.provision 'file', source: '../deploy/units',
79 | destination: '/tmp'
80 |
81 | config.vm.provision 'file', source: '../deploy/git/post-receive',
82 | destination: '/tmp'
83 |
84 | # Move the files with sudo into the correct remote location.
85 | config.vm.provision 'shell',
86 | inline: 'sudo mv /tmp/certs/rediscounter.crt /etc/ssl/certs'
87 |
88 | config.vm.provision 'shell',
89 | inline: 'sudo mv /tmp/certs/rediscounter.key /etc/ssl/private'
90 |
91 | config.vm.provision 'shell',
92 | inline: 'sudo mv /tmp/certs/dhparam.pem /etc/ssl/private'
93 |
94 | config.vm.provision 'shell',
95 | inline: 'sudo mv /tmp/units/redis.service /etc/systemd/system'
96 |
97 | config.vm.provision 'shell',
98 | inline: 'sudo mv /tmp/units/nginx.service /etc/systemd/system'
99 |
100 | config.vm.provision 'shell',
101 | inline: 'sudo mv /tmp/units/rediscounter.service /etc/systemd/system'
102 |
103 | config.vm.provision 'shell',
104 | inline: 'mv /tmp/post-receive/nginx /var/git/nginx.git/hooks/post-receive'
105 |
106 | config.vm.provision 'shell',
107 | inline: 'mv /tmp/post-receive/rediscounter /var/git/rediscounter.git/hooks/post-receive'
108 |
109 | # Set proper permissions.
110 | config.vm.provision 'shell',
111 | inline: 'chmod +x /var/git/nginx.git/hooks/post-receive /var/git/rediscounter.git/hooks/post-receive'
112 |
113 |
114 | # Pull in any Docker images we need.
115 | config.vm.provision 'shell',
116 | inline: 'docker pull redis:2.8.21'
117 |
118 | # Enable and start Redis through systemd, this ensures it loads on bootup.
119 | config.vm.provision 'shell',
120 | inline: 'sudo systemctl enable redis.service && sudo systemctl start redis.service'
121 |
122 | # **************************************************************************
123 | # A few commands need to be ran on your `workstation` before proceeding.
124 | # --------------------------------------------------------------------------
125 | # Consult with Chapter 8 of the book to see the details.
126 | # **************************************************************************
127 |
128 | # **************************************************************************
129 | # A few commands need to be ran on the `CoreOS host` before proceeding.
130 | # --------------------------------------------------------------------------
131 | # Consult with Chapter 8 of the book to see the details.
132 | # **************************************************************************
133 | end
134 | end
135 |
--------------------------------------------------------------------------------
/chapter-8/website/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask
2 | from redis import StrictRedis
3 |
4 | app = Flask(__name__)
5 | redis = StrictRedis(host='redis')
6 |
7 | @app.route('/')
8 | def hello_world():
9 | hits = redis.incr('hits')
10 | return 'You visited {0} times!'.format(hits)
11 |
12 | if __name__ == '__main__':
13 | app.run(host='0.0.0.0', port=8000, debug=True)
14 |
--------------------------------------------------------------------------------
/chapter-8/website/docker-compose.yml:
--------------------------------------------------------------------------------
1 | redis:
2 | image: redis:2.8.21
3 | ports:
4 | - 6379:6379
5 | volumes:
6 | - ~/.docker-volumes/rediscounter/redis/data:/var/lib/redis/data
7 |
8 | website:
9 | build: .
10 | links:
11 | - redis
12 | volumes:
13 | - .:/rediscounter
14 | ports:
15 | - 8000:8000
16 |
17 | cadvisor:
18 | image: google/cadvisor:latest
19 | volumes:
20 | - /:/rootfs:ro
21 | - /var/run:/var/run:rw
22 | - /sys:/sys:ro
23 | - /var/lib/docker/:/var/lib/docker:ro
24 | ports:
25 | - 8080:8080
26 |
--------------------------------------------------------------------------------
/chapter-8/website/requirements.txt:
--------------------------------------------------------------------------------
1 | Flask==0.10.1
2 | redis==2.10.3
3 |
--------------------------------------------------------------------------------
/chapter-9/deploy/git/post-receive/nginx:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Configuration.
4 | REPO_NAME="nginx"
5 |
6 | # Check out the newest version of the code.
7 | export GIT_WORK_TREE="/var/git/${REPO_NAME}"
8 | git checkout -f
9 |
10 | TAG="$(git log --pretty=format:'%h' -n 1)"
11 | FULL_COMMIT_TAG="${REPO_NAME}:${TAG}"
12 | FULL_LATEST_TAG="${REPO_NAME}:latest"
13 |
14 | # Build the image with the proper commit tag.
15 | docker build -t "${FULL_COMMIT_TAG}" "${GIT_WORK_TREE}"
16 |
17 | # Get the Docker ID of the last built image.
18 | DOCKER_ID="$(docker images -q $REPO_NAME | head -1)"
19 |
20 | # Tag a latest version based off the proper commit tag.
21 | docker tag -f "${DOCKER_ID}" "${FULL_LATEST_TAG}"
22 |
23 | echo "Restarting ${REPO_NAME}"
24 | docker stop "${REPO_NAME}"
25 |
26 | echo "Removing untagged Docker images (may take a while)"
27 | docker rmi $(docker images --quiet --filter "dangling=true")
28 |
--------------------------------------------------------------------------------
/chapter-9/deploy/git/post-receive/rediscounter:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Configuration.
4 | REPO_NAME="rediscounter"
5 |
6 | # Check out the newest version of the code.
7 | export GIT_WORK_TREE="/var/git/${REPO_NAME}"
8 | git checkout -f
9 |
10 | TAG="$(git log --pretty=format:'%h' -n 1)"
11 | FULL_COMMIT_TAG="${REPO_NAME}:${TAG}"
12 | FULL_LATEST_TAG="${REPO_NAME}:latest"
13 |
14 | # Build the image with the proper commit tag.
15 | docker build -t "${FULL_COMMIT_TAG}" "${GIT_WORK_TREE}"
16 |
17 | # Get the Docker ID of the last built image.
18 | DOCKER_ID="$(docker images -q $REPO_NAME | head -1)"
19 |
20 | # Tag a latest version based off the proper commit tag.
21 | docker tag -f "${DOCKER_ID}" "${FULL_LATEST_TAG}"
22 |
23 | echo "Restarting ${REPO_NAME}"
24 | docker stop "${REPO_NAME}"
25 |
26 | echo "Removing untagged Docker images (may take a while)"
27 | docker rmi $(docker images --quiet --filter "dangling=true")
28 |
29 | echo "Restarting nginx"
30 | docker stop "nginx"
31 |
--------------------------------------------------------------------------------
/chapter-9/deploy/nginx/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM nginx:1.9.3
2 | MAINTAINER Nick Janetakis
3 |
4 | # Delete default static pages.
5 | RUN rm /usr/share/nginx/html/*
6 |
7 | # Copy over the custom nginx and default configs.
8 | COPY configs/nginx.conf /etc/nginx/nginx.conf
9 | COPY configs/default.conf /etc/nginx/conf.d/default.conf
10 |
11 | # Copy over the self signed SSL certificates.
12 | COPY certs/rediscounter.crt /etc/ssl/certs/rediscounter.crt
13 | COPY certs/rediscounter.key /etc/ssl/private/rediscounter.key
14 | COPY certs/dhparam.pem /etc/ssl/private/dhparam.pem
15 |
16 | # Allow us to customize the entry point of the image.
17 | COPY docker-entrypoint /
18 | RUN chmod +x /docker-entrypoint
19 | ENTRYPOINT ["/docker-entrypoint"]
20 |
21 | # Start nginx in the foreground.
22 | CMD ["nginx", "-g", "daemon off;"]
--------------------------------------------------------------------------------
/chapter-9/deploy/nginx/certs/dhparam.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN DH PARAMETERS-----
2 | MIIBCAKCAQEA4ZvlxM3OiUA+WWjQolRqxLazGeM0sVwXUJLpPlVrjZH/9Slo7ovq
3 | VZhFgBTZToXZlO+rG77/7XvkLxOwa/Bxj9sEyieObFh5M3AYpqPliotsPDNvNl1l
4 | Ys09k+mYUqW/WToVHburvDAHLseHBiRPTkKMEgZ79wZE9SHiHXOJnNSb2HvgfnHz
5 | 4QM+e/z4Yx1q22TF+lACm/zIFrPhUQpu5RkF7R3jwurVdWa5XyVljGPlnQXbeBns
6 | fECKaU2wsQc2+t5gpkdxDlX7ZDQ9Nh+DkW0WCrGyLm2cBfP2qm5X4RL1ge3LZzYC
7 | CpHZ7NCtHFneOUtlZ+XMLxHbseosm2PNYwIBAg==
8 | -----END DH PARAMETERS-----
9 |
--------------------------------------------------------------------------------
/chapter-9/deploy/nginx/certs/rediscounter.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDhzCCAm+gAwIBAgIJAJFkaQ5PfmT8MA0GCSqGSIb3DQEBCwUAMFoxCzAJBgNV
3 | BAYTAlVTMRAwDgYDVQQIDAdOZXdZb3JrMRAwDgYDVQQHDAdOZXdZb3JrMQswCQYD
4 | VQQKDAJJVDEaMBgGA1UEAwwRbG9jYWxyZWdpc3RyeS5jb20wHhcNMTUwODAzMTQx
5 | MDAyWhcNMjUwNzMxMTQxMDAyWjBaMQswCQYDVQQGEwJVUzEQMA4GA1UECAwHTmV3
6 | WW9yazEQMA4GA1UEBwwHTmV3WW9yazELMAkGA1UECgwCSVQxGjAYBgNVBAMMEWxv
7 | Y2FscmVnaXN0cnkuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
8 | 3QgNGc1Dpf4SMls0R/RroX7d6cniisI2XgspVHHYW8hDx/NO8NdZf3KCD9T+SAVg
9 | 9DddbGx7StxhMnB1lW7HmeOzGFR4NjOuh4fz0iYYoLRd4gzkit0D+OSBsnr4tLle
10 | yysEC0wYkLAHCHeZlZ9u54DTW9bzGW4KNFAkLagBQMGcg2bkXpqOr1xrO+6uc5IV
11 | 8VM6yoedXlDek6K0rsxRUmh/8jcEXMwFTqmnTexShYVB+Ji5XLPgikSOmQje+3JF
12 | 1tE8rIsPhF98mWz/wRRBaV+5LJtTM54TXmi4BrmMALKM0Lo1khvWitwIfPOJWGEX
13 | VJllkJARv2KFX87vkEv6dQIDAQABo1AwTjAdBgNVHQ4EFgQUnUGjY1oLqT00U7y2
14 | iGOSgpx6EZkwHwYDVR0jBBgwFoAUnUGjY1oLqT00U7y2iGOSgpx6EZkwDAYDVR0T
15 | BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAeS06ifrHBKZ700o4bjEt2vFg1pcK
16 | abk8Bw7Vcn2RvDB09lJg3UFRs6CrJFqOnVF+AUA2goB8UKP7/LeYnN00DdZsLRi9
17 | sY93agdq95iv62+VdCnA+XleDS01wQFwzOlXb7p76y9a/v3SItMB9viXZ93wIo8E
18 | C0Owql0tvevvxqkxPru2QQO6JOzA70mQ19vQJsdBuviTeGMul7trZeOTmDRlR5vT
19 | u9h5Xk5bLV50H56MlZNOJvY+rnX+yk2Qgru2HDlOwb2vYYOZvSqiAHCuIB3VslpP
20 | iX0gAyV5WeSxmLQna6IxJIuNUUdq4UR6ZoACz69DQa1WO+dbs9jWseD5Cg==
21 | -----END CERTIFICATE-----
22 |
--------------------------------------------------------------------------------
/chapter-9/deploy/nginx/certs/rediscounter.key:
--------------------------------------------------------------------------------
1 | -----BEGIN PRIVATE KEY-----
2 | MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDdCA0ZzUOl/hIy
3 | WzRH9Guhft3pyeKKwjZeCylUcdhbyEPH807w11l/coIP1P5IBWD0N11sbHtK3GEy
4 | cHWVbseZ47MYVHg2M66Hh/PSJhigtF3iDOSK3QP45IGyevi0uV7LKwQLTBiQsAcI
5 | d5mVn27ngNNb1vMZbgo0UCQtqAFAwZyDZuRemo6vXGs77q5zkhXxUzrKh51eUN6T
6 | orSuzFFSaH/yNwRczAVOqadN7FKFhUH4mLlcs+CKRI6ZCN77ckXW0Tysiw+EX3yZ
7 | bP/BFEFpX7ksm1MznhNeaLgGuYwAsozQujWSG9aK3Ah884lYYRdUmWWQkBG/YoVf
8 | zu+QS/p1AgMBAAECggEBANG7sQq5rqZU5xlnV72rXXIZuyL7UX7PeN1WA/rAKEg3
9 | SLHz2wVHowH/OxEgz8SxbeVun7ShX4CSi5xcAAcy3i3VVX0RshvkgIjUZXUUdywO
10 | 2kMEbtyhigJjefpNG7AJcbyhba32oByzG4laS58hcRA1OtmbpoOL2hz3qsyz7bRt
11 | /vVaJHFTm6CSz9Wn/m2xWmyLJn3ObHE8AMp8FteztkcNceqGWpga99u6PSMFJ0G8
12 | JT/RDUUO2WA5hf0GmJbBTyqx6977ivFGeYhXrlpOxxVxkx0x+Gd7p/F/FNhGmr1l
13 | qIa+z+NcWOxKV30BG7Ra9A0doxVIojQCASLkPN3rXAECgYEA/QELsstfvSmdZvUJ
14 | 6Ox3g+Ozxxm5w0tiCEaeC0nlsrENPabSq9xEs2jbKhww5ox3sPs6OKusRD6YPE2t
15 | Eq/uEVyn+oGOr+J4Q4zQTDNrd2QAYGMZRNuZkTOFpe8KZBmTIo4mCtEGp2SUSJcC
16 | uL6cO6DbwSikrijHvkFu6YpMSQECgYEA36YVe9Uz0xLbmtxeYVSijeEfvfNRDjys
17 | cbjAI6eFmntR8XTmEWoZVRKmA9kDg9IlK82vZeEqMlEviagO6eAjl6rC9lxfBTUl
18 | BbQWaAFZGimQInk0cWiHc8AhdOK+H7LKaEMIycMNu2AUoWBN/Mc9CGy8DFrc3RRQ
19 | FuYrXWGpnXUCgYEAqpks6TfHa8cG0ujB8OSaRj2g+Mz4/J31EX2Ejjoa/53xPrQh
20 | dC9Hx+4ZclCmDJ+FCbqtbI8dzrqibm82F9a3Yc+nmPwJWcIMtAfcYLV/bnbo5hWM
21 | cWjeKRGjudrwl8TC+Nb/AeYmZXMlpbjl5erpcC+sXpfoS2NGJJz8i89sVwECgYBP
22 | ZYTG+390dYNkzMrsvsEeoUdFhfXGmh+WF8KOZdB2cUU79QYgNIxduUsanpYy3A26
23 | KUEVaAQ07MF1myYAPUQlecfQ8iYBkUZdaftyXNgnA45ZzrGheTxtCU5XUo+wbSaS
24 | MQoTpp1fYdKxH6FQFeNC9Gcl87PpAGcWWgwXEK7IaQKBgQDn7kAAlxOYNQye8320
25 | IfOoUyzFMLotlGclqKvkhLEDmg5aUEurdOAR01qSQt2OcJ5AlXJ2UJpsOCx7cXg2
26 | qt37wOz5F0L5jsHuPDLImQm2rdPuWZH2VwrYF71ejkmAw1sAOaPQCYpl8wGbKGRt
27 | y7ZDJzUMJ6e3JMLVYcOBIvRLGw==
28 | -----END PRIVATE KEY-----
29 |
--------------------------------------------------------------------------------
/chapter-9/deploy/nginx/configs/default.conf:
--------------------------------------------------------------------------------
1 | upstream rediscounter {
2 | # The Flask application.
3 | server rediscounter:8000;
4 | }
5 |
6 | # In case you want 'www' addresses to be automatically redirected without 'www'.
7 | # server {
8 | # listen 80;
9 | # listen 443;
10 | # server_name www.yourrealdomain.com;
11 | # return 301 https://yourrealdomain.com$request_uri;
12 | #}
13 |
14 | server {
15 | listen 80 default deferred;
16 | server_name 172.17.8.101;
17 |
18 | # All http traffic will get redirected to SSL.
19 | return 307 https://$host$request_uri;
20 | }
21 |
22 | server {
23 | # "deferred" reduces the number of formalities between the server and client.
24 | listen 443 default deferred;
25 | server_name 172.17.8.101;
26 |
27 | # Static asset path, which is read from the rediscounter's VOLUME. In this
28 | # case the example application has no assets, but this is how you would
29 | # configure assets to be served through nginx.
30 | root /rediscounter/build/public;
31 |
32 | # Ensure timeouts are equal across browsers and raise the max content-length size.
33 | keepalive_timeout 60;
34 | client_max_body_size 5m;
35 |
36 | # SSL goodness.
37 | ssl on;
38 | ssl_certificate /etc/ssl/certs/rediscounter.crt;
39 | ssl_certificate_key /etc/ssl/private/rediscounter.key;
40 | ssl_session_cache shared:SSL:50m;
41 | ssl_session_timeout 5m;
42 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
43 | ssl_prefer_server_ciphers on;
44 | ssl_ciphers "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA";
45 | ssl_dhparam /etc/ssl/private/dhparam.pem;
46 | ssl_ecdh_curve secp384r1;
47 | add_header Strict-Transport-Security 'max-age=63072000; includeSubDomains;' always;
48 |
49 | # Disallow access to hidden files and directories.
50 | location ~ /\. {
51 | return 404;
52 | access_log off;
53 | log_not_found off;
54 | }
55 |
56 | # Allow optionally writing an index.html file to take precedence over the upstream.
57 | try_files $uri $uri/index.html $uri.html @rediscounter;
58 |
59 | # Attempt to load the favicon or fall back to status code 204.
60 | location = /favicon.ico {
61 | try_files /favicon.ico = 204;
62 | access_log off;
63 | log_not_found off;
64 | }
65 |
66 | # Load the Flask app back end with proper headers.
67 | location @rediscounter {
68 | proxy_set_header X-Forwarded-Proto $scheme;
69 | proxy_set_header Host $http_host;
70 | proxy_set_header X-Real-IP $remote_addr;
71 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
72 | proxy_redirect off;
73 | proxy_pass http://rediscounter;
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/chapter-9/deploy/nginx/configs/nginx.conf:
--------------------------------------------------------------------------------
1 | # Number of workers to run, usually equals number of CPU cores.
2 | worker_processes auto;
3 |
4 | # Maximum number of opened files per process.
5 | worker_rlimit_nofile 4096;
6 |
7 | events {
8 | # Maximum number of simultaneous connections that can be opened by a worker process.
9 | worker_connections 1024;
10 | }
11 |
12 | http {
13 | include /etc/nginx/mime.types;
14 | default_type application/octet-stream;
15 |
16 | # ---------------------------------------------------------------------------
17 | # Security settings from:
18 | # https://gist.github.com/plentz/6737338
19 |
20 | # Disable nginx version from being displayed on errors.
21 | server_tokens off;
22 |
23 | # config to don't allow the browser to render the page inside an frame or iframe
24 | # and avoid clickjacking http://en.wikipedia.org/wiki/Clickjacking
25 | # if you need to allow [i]frames, you can use SAMEORIGIN or even set an uri with ALLOW-FROM uri
26 | # https://developer.mozilla.org/en-US/docs/HTTP/X-Frame-Options
27 | add_header X-Frame-Options SAMEORIGIN;
28 |
29 | # when serving user-supplied content, include a X-Content-Type-Options: nosniff header along with the Content-Type: header,
30 | # to disable content-type sniffing on some browsers.
31 | # https://www.owasp.org/index.php/List_of_useful_HTTP_headers
32 | # currently suppoorted in IE > 8 http://blogs.msdn.com/b/ie/archive/2008/09/02/ie8-security-part-vi-beta-2-update.aspx
33 | # http://msdn.microsoft.com/en-us/library/ie/gg622941(v=vs.85).aspx
34 | # 'soon' on Firefox https://bugzilla.mozilla.org/show_bug.cgi?id=471020
35 | add_header X-Content-Type-Options nosniff;
36 |
37 | # This header enables the Cross-site scripting (XSS) filter built into most recent web browsers.
38 | # It's usually enabled by default anyway, so the role of this header is to re-enable the filter for
39 | # this particular website if it was disabled by the user.
40 | # https://www.owasp.org/index.php/List_of_useful_HTTP_headers
41 | add_header X-XSS-Protection "1; mode=block";
42 | # ---------------------------------------------------------------------------
43 |
44 | # Avoid situations where a hostname is too long when dealing with vhosts.
45 | server_names_hash_bucket_size 64;
46 | server_names_hash_max_size 512;
47 |
48 | # Performance optimizations.
49 | sendfile on;
50 | tcp_nopush on;
51 |
52 | # http://nginx.org/en/docs/hash.html
53 | types_hash_max_size 2048;
54 |
55 | # Enable gzip for everything but IE6.
56 | gzip on;
57 | gzip_disable "msie6";
58 |
59 | # Default config for the app backend.
60 | include /etc/nginx/conf.d/default.conf;
61 | }
62 |
--------------------------------------------------------------------------------
/chapter-9/deploy/nginx/docker-entrypoint:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -e
3 |
4 | # Overwrite a few variables, this allows us to use the same template
5 | # for both development, staging and production.
6 | CONFIG_PATH="/etc/nginx/conf.d/default.conf"
7 | STAGING_IP="172.17.8.101"
8 | STAGING_HOSTNAME="core-01"
9 | DOMAIN_NAME="yourrealdomain.com"
10 |
11 | if [[ $(hostname) != "${STAGING_HOSTNAME}" ]]; then
12 | sed -i "s/${STAGING_IP}/${DOMAIN_NAME}/g" "${CONFIG_PATH}"
13 | fi
14 |
15 | # Execute the CMD from the Dockerfile.
16 | exec "$@"
17 |
--------------------------------------------------------------------------------
/chapter-9/deploy/production/rules-save:
--------------------------------------------------------------------------------
1 | *filter
2 |
3 | :INPUT DROP [0:0]
4 | :FORWARD DROP [0:0]
5 | :OUTPUT ACCEPT [0:0]
6 |
7 | -A INPUT -i lo -j ACCEPT
8 | -A INPUT -i eth1 -j ACCEPT
9 | -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
10 | -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
11 | -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
12 | -A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
13 | -A INPUT -p icmp -m icmp --icmp-type 0 -j ACCEPT
14 | -A INPUT -p icmp -m icmp --icmp-type 3 -j ACCEPT
15 | -A INPUT -p icmp -m icmp --icmp-type 11 -j ACCEPT
16 |
17 | COMMIT
18 |
--------------------------------------------------------------------------------
/chapter-9/deploy/units/nginx.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Run %p
3 | Requires=docker.service rediscounter.service
4 | After=docker.service rediscounter.service
5 |
6 | [Service]
7 | Restart=always
8 | ExecStartPre=-/usr/bin/docker kill %p
9 | ExecStartPre=-/usr/bin/docker rm -f %p
10 | ExecStart=/usr/bin/docker run -t --rm --name %p \
11 | -p 80:80 -p 443:443 \
12 | --link rediscounter:rediscounter \
13 | -v /etc/ssl/certs:/etc/ssl/certs \
14 | -v /etc/ssl/private:/etc/ssl/private %p
15 | ExecStop=/usr/bin/docker stop %p
16 |
17 | [Install]
18 | WantedBy=multi-user.target
19 |
--------------------------------------------------------------------------------
/chapter-9/deploy/units/redis.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Run %p
3 | Requires=docker.service
4 | After=docker.service
5 |
6 | [Service]
7 | Restart=always
8 | ExecStartPre=-/usr/bin/mkdir -p /var/lib/%p/data
9 | ExecStartPre=-/usr/bin/docker kill %p
10 | ExecStartPre=-/usr/bin/docker rm -f %p
11 | ExecStart=/usr/bin/docker run --rm --name %p \
12 | -v /var/lib/%p/data:/var/lib/%p/data -p 6379:6379 %p:2.8.21
13 | ExecStop=/usr/bin/docker stop %p
14 |
15 | [Install]
16 | WantedBy=multi-user.target rediscounter.service
17 |
--------------------------------------------------------------------------------
/chapter-9/deploy/units/rediscounter.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Run %p
3 | Requires=docker.service redis.service
4 | After=docker.service redis.service
5 |
6 | [Service]
7 | Restart=always
8 | ExecStartPre=-/usr/bin/docker kill %p
9 | ExecStartPre=-/usr/bin/docker rm -f %p
10 | ExecStart=/usr/bin/docker run -t --rm --name %p \
11 | --link redis:redis -p 8000:8000 %p
12 | ExecStartPost=-/usr/bin/docker stop nginx
13 | ExecStop=/usr/bin/docker stop %p
14 |
15 | [Install]
16 | WantedBy=multi-user.target nginx.service
17 |
--------------------------------------------------------------------------------
/chapter-9/website/.dockerignore:
--------------------------------------------------------------------------------
1 | .git
2 | tmp/*
3 | log/*
4 | .dockerignore
5 | .vagrant/
6 |
--------------------------------------------------------------------------------
/chapter-9/website/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 |
5 | # OS and editor files
6 | .DS_Store
7 | */**.DS_Store
8 | ._*
9 | .*.sw*
10 | *~
11 | .idea/
12 | .mr.developer.cfg
13 | .project
14 | .pydevproject
15 | *.tmproj
16 | *.tmproject
17 | tmtags
18 |
19 | .vagrant/
20 |
--------------------------------------------------------------------------------
/chapter-9/website/Dockerfile:
--------------------------------------------------------------------------------
1 | # Use the barebones version of Python 2.7.10.
2 | FROM python:2.7.10-slim
3 | MAINTAINER Nick Janetakis
4 |
5 | # Install any packages that must be installed.
6 | RUN apt-get update && apt-get install -qq -y build-essential --fix-missing --no-install-recommends
7 |
8 | # Set up the install path for this service.
9 | ENV INSTALL_PATH /rediscounter
10 | RUN mkdir -p $INSTALL_PATH
11 |
12 | # Update the workdir to be where our app is installed.
13 | WORKDIR $INSTALL_PATH
14 |
15 | # Ensure packages are cached and only get updated when necessary. If we didn’t do this step then every time we pushed an app change it would also re-run pip install, even if no packages changed.
16 | COPY requirements.txt requirements.txt
17 | RUN pip install -r requirements.txt
18 |
19 | # Copy the source from your workstation to the image at the WORKDIR path.
20 | COPY . .
21 |
22 | # Create a volume so that nginx can read from it.
23 | VOLUME ["$INSTALL_PATH/build/public"]
24 |
25 | # The default command to run if no command is specified.
26 | CMD python app.py
27 |
--------------------------------------------------------------------------------
/chapter-9/website/Vagrantfile:
--------------------------------------------------------------------------------
1 | Vagrant.require_version '>= 1.6.0'
2 |
3 | # Configuration settings for the Virtual Machine.
4 | $update_channel = 'beta'
5 | $image_version = 'current'
6 | $vm_memory = 1024
7 | $vm_cpus = 1
8 | $forwarded_ports = {
9 | '80' => '8080',
10 | '443' => '8081'
11 | }
12 | $vm_host = 'core-01'
13 | $vm_ip = '172.17.8.101'
14 |
15 | Vagrant.configure('2') do |config|
16 | config.ssh.insert_key = false
17 | config.ssh.forward_agent = true
18 |
19 | config.vm.box = 'coreos-%s' % [$update_channel]
20 | if $image_version != 'current'
21 | config.vm.box_version = $image_version
22 | end
23 | config.vm.box_url = 'http://%s.release.core-os.net/amd64-usr/%s/coreos_production_vagrant.json' % [$update_channel, $image_version]
24 |
25 | ['vmware_fusion', 'vmware_workstation'].each do |vmware|
26 | config.vm.provider vmware do |v, override|
27 | override.vm.box_url = 'http://%s.release.core-os.net/amd64-usr/%s/coreos_production_vagrant_vmware_fusion.json' % [$update_channel, $image_version]
28 | end
29 | end
30 |
31 | config.vm.provider :virtualbox do |v|
32 | v.check_guest_additions = false
33 | v.functional_vboxsf = false
34 | end
35 |
36 | if Vagrant.has_plugin?('vagrant-vbguest') then
37 | config.vbguest.auto_update = false
38 | end
39 |
40 | config.vm.define vm_name = $vm_host do |config|
41 | config.vm.hostname = vm_name
42 |
43 | config.vm.network :private_network, ip: $vm_ip
44 |
45 | $forwarded_ports.each do |guest, host|
46 | config.vm.network 'forwarded_port', guest: guest, host: host, auto_correct: true
47 | end
48 |
49 | ['vmware_fusion', 'vmware_workstation'].each do |vmware|
50 | config.vm.provider vmware do |v|
51 | v.gui = false
52 | v.vmx['memsize'] = $vm_memory
53 | v.vmx['numvcpus'] = $vm_cpus
54 | end
55 | end
56 |
57 | config.vm.provider :virtualbox do |vb|
58 | vb.gui = false
59 | vb.memory = $vm_memory
60 | vb.cpus = $vm_cpus
61 | end
62 |
63 | # Create bare git repos.
64 | config.vm.provision 'shell',
65 | inline: 'sudo mkdir -p /var/git/nginx.git /var/git/nginx /var/git/rediscounter.git /var/git/rediscounter'
66 |
67 | config.vm.provision 'shell',
68 | inline: 'sudo su && cd /var/git/nginx.git && git --bare init && chown -R core:core /var/git/nginx.git && chown -R core:core /var/git/nginx'
69 |
70 | config.vm.provision 'shell',
71 | inline: 'sudo su && cd /var/git/rediscounter.git && git --bare init && chown -R core:core /var/git/rediscounter.git && chown -R core:core /var/git/rediscounter'
72 |
73 |
74 | # Copy files into the VM instance upon provision.
75 | config.vm.provision 'file', source: '../deploy/nginx/certs',
76 | destination: '/tmp'
77 |
78 | config.vm.provision 'file', source: '../deploy/units',
79 | destination: '/tmp'
80 |
81 | config.vm.provision 'file', source: '../deploy/git/post-receive',
82 | destination: '/tmp'
83 |
84 | # Move the files with sudo into the correct remote location.
85 | config.vm.provision 'shell',
86 | inline: 'sudo mv /tmp/certs/rediscounter.crt /etc/ssl/certs'
87 |
88 | config.vm.provision 'shell',
89 | inline: 'sudo mv /tmp/certs/rediscounter.key /etc/ssl/private'
90 |
91 | config.vm.provision 'shell',
92 | inline: 'sudo mv /tmp/certs/dhparam.pem /etc/ssl/private'
93 |
94 | config.vm.provision 'shell',
95 | inline: 'sudo mv /tmp/units/redis.service /etc/systemd/system'
96 |
97 | config.vm.provision 'shell',
98 | inline: 'sudo mv /tmp/units/nginx.service /etc/systemd/system'
99 |
100 | config.vm.provision 'shell',
101 | inline: 'sudo mv /tmp/units/rediscounter.service /etc/systemd/system'
102 |
103 | config.vm.provision 'shell',
104 | inline: 'mv /tmp/post-receive/nginx /var/git/nginx.git/hooks/post-receive'
105 |
106 | config.vm.provision 'shell',
107 | inline: 'mv /tmp/post-receive/rediscounter /var/git/rediscounter.git/hooks/post-receive'
108 |
109 | # Set proper permissions.
110 | config.vm.provision 'shell',
111 | inline: 'chmod +x /var/git/nginx.git/hooks/post-receive /var/git/rediscounter.git/hooks/post-receive'
112 |
113 |
114 | # Pull in any Docker images we need.
115 | config.vm.provision 'shell',
116 | inline: 'docker pull redis:2.8.21'
117 |
118 | # Enable and start Redis through systemd, this ensures it loads on bootup.
119 | config.vm.provision 'shell',
120 | inline: 'sudo systemctl enable redis.service && sudo systemctl start redis.service'
121 |
122 | # **************************************************************************
123 | # A few commands need to be ran on your `workstation` before proceeding.
124 | # --------------------------------------------------------------------------
125 | # Consult with Chapter 8 of the book to see the details.
126 | # **************************************************************************
127 |
128 | # **************************************************************************
129 | # A few commands need to be ran on the `CoreOS host` before proceeding.
130 | # --------------------------------------------------------------------------
131 | # Consult with Chapter 8 of the book to see the details.
132 | # **************************************************************************
133 | end
134 | end
135 |
--------------------------------------------------------------------------------
/chapter-9/website/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask
2 | from redis import StrictRedis
3 |
4 | app = Flask(__name__)
5 | redis = StrictRedis(host='redis')
6 |
7 | @app.route('/')
8 | def hello_world():
9 | hits = redis.incr('hits')
10 | return 'You visited {0} times!'.format(hits)
11 |
12 | if __name__ == '__main__':
13 | app.run(host='0.0.0.0', port=8000, debug=True)
14 |
--------------------------------------------------------------------------------
/chapter-9/website/docker-compose.yml:
--------------------------------------------------------------------------------
1 | redis:
2 | image: redis:2.8.21
3 | ports:
4 | - 6379:6379
5 | volumes:
6 | - ~/.docker-volumes/rediscounter/redis/data:/var/lib/redis/data
7 |
8 | website:
9 | build: .
10 | links:
11 | - redis
12 | volumes:
13 | - .:/rediscounter
14 | ports:
15 | - 8000:8000
16 |
17 | cadvisor:
18 | image: google/cadvisor:latest
19 | volumes:
20 | - /:/rootfs:ro
21 | - /var/run:/var/run:rw
22 | - /sys:/sys:ro
23 | - /var/lib/docker/:/var/lib/docker:ro
24 | ports:
25 | - 8080:8080
26 |
--------------------------------------------------------------------------------
/chapter-9/website/requirements.txt:
--------------------------------------------------------------------------------
1 | Flask==0.10.1
2 | redis==2.10.3
3 |
--------------------------------------------------------------------------------