0) Student
1) starting A levels
3) gave a lightening talk last year
2) @lukespademan: [twitter, git, etc]
Deops is trying to automate stuff you would normaly have to do manually.
pip install pipenv --usermkdir project
cd project
mkdir src
cd srcpipenv python --3.6 # creates the virtual environment
pipenv install django gunicorn psycopg2-binary # installs pakcages to venv
pipenv shell # enteres the virtual environment
django-admin startproject mysite .django-admin startproject mysite .# src/mysite/settings.py
# ...
try:
SECRET_KEYexcept NameError:
SECRET_FILE = os.path.join(BASE_DIR, 'secret.txt')
try:
SECRET_KEY = open(SECRET_FILE).read().strip() except IOError:
try:
import random
SECRET_KEY = ''.join([random.SystemRandom().choice(
'abcdefghijklmnopqrstuvxyz0123456789!@#$%^&*(-_=+)') for i in range(50)]
) secret = open(SECRET_FILE, "w")
secret.write(SECRET_KEY)
secret.close() except IOError:
Exception("Please create a %s file with random characters." % SECRET_FILE)
# ...# src/mysite/settings.py
# ...
# SECURITY WARNING: don't run with debug turned on in production!if os.environ.get('DJANGO_DEBUG'):
print("Debug is enabled.")
DEBUG = True
ALLOWED_HOSTS = ["localhost", "127.0.0.1"]
else:
DEBUG = False
ALLOWED_HOSTS = ["example.com", "localhost"]
# ...# src/mysite/settings.py
# ...else:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'postgres',
'USER': 'postgres',
'HOST': 'db',
'PORT': 5432,
}
}
# ...if DEBUG == True:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}# src/mysite/settings.py
# ...
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.0/howto/static-files/STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, "static/")
.
└── src
├── db.sqlite3
├── main.py
├── manage.py
├── mysite
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── Pipfile
├── Pipfile.lock
└── secret.txtcd srcpipenv shellDJANGO_DEBUG=True python manage.py makemigrations
DJANGO_DEBUG=True python manage.py migrateDJANGO_DEBUG=True python manage.py runserverpython manage.py startapp hello_world# src/hello_world/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
]
# src/hello_world/views.py
from django.shortcuts import render
def index(request):
return render(request, 'hello_world/index.html')
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello, PyCon UK!</title>
</head>
<body>
<h1>Hello, PyCon UK!</h1>
</body>
</html>
# src/hello_world/templates/hello_world/index.html# src/mysite/settings.py
...
INSTALLED_APPS = [
'hello_world',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
...# src/mysite/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('hello_world.urls')),
]
# DockerfileFORM python:3.6RUN mkdir /src
ADD src/Pipfile /src
ADD src/Pipfile.lock /srcRUN pip install pipenvWORKDIR /src
RUN pipenv install --system --deploy --ignore-pipfileADD src /src# docker-compose.ymlversion: '3'
services:
nginx:
image: registry.gitlab.com/lukespademan/mysite/nginx:latest
build:
context: .
dockerfile: Dockerfile.nginx
container_name: mysite_nginx
depends_on:
- web
ports:
- "80:8080"
web:
image: registry.gitlab.com/lukespademan/mysite:latest
build: .
container_name: mysite_django
command: bash start_django.sh
depends_on:
- db
db:
image: postgres:latest
container_name: mysite_postgres
volumes:
- "db:/var/lib/postgresql/data"
volumes:
db: {}
services:
nginx:
build: Dockerfile.nginx
container_name: mysite_nginx
depends_on:
- web
ports:
- "80:8080" web:
build: .
container_name: mysite_django
command: bash start_django.sh
depends_on:
- db db:
image: postgres:latest
container_name: mysite_postgres
volumes:
- "db:/var/lib/postgresql/data"volumes:
db: {}# src/start_django.sh#!/bin/bash
ls
cat Pipfile
pip freeze
python manage.py migrate
python manage.py collectstatic --noinput
gunicorn mysite.wsgi -b 0.0.0.0:8000
FROM nginx:latestADD config/nginx /etc/nginx/conf.d
ADD src /src
EXPOSE 80
mkdir config
cd configmkdir nginx
cd nginx# config/nginx/my_django.conf
upstream web {
ip_hash;
server web:8000;
}upstream web {
ip_hash;
server web:8000;
}server {
location /robots.txt {alias /src/static/robots.txt;}
location /favicon.ico {alias /src/static/favicon.ico;}
location /static/ {
autoindex on;
alias /src/static/;
} location / {
proxy_pass http://web/;
}
listen 8080;
}
.
└── config
│ └── nginx
│ └── my_django.conf
├── docker-compose.yml
├── Dockerfile
└── src
├── db.sqlite3
├── main.py
├── manage.py
├── mysite
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── Pipfile
├── Pipfile.lock
├── secret.txt
└── start_django.shsudo docker-compose buildsudo docker-compose up# .gitignore
__pycache__
db.sqlite3
secret.txt# Devops ExampleMIT License
Copyright (c) 2018 Luke Spademan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh | \
sudo bashsudo apt-get install gitlab-runnersudo gitlab-runner register# /etc/gitlab-runner/config.toml
...
volumes = ["cache", "/var/run/docker.sock:/var/run/docker.sock"]
...sudo docker login registry.gitlab.comsudo gitlab-runner startsudo docker warm init --advertise-addr 123.123.123.123image: tmaier/docker-compose:latest
stages:
- build
- test
- deploy
variables:
WEB_CONTAINER_IMAGE: registry.gitlab.com/lukespademan/mysite:latest
NGINX_CONTAINER_IMAGE: registry.gitlab.com/lukespademan/mysite/nginx:latest
before_script:
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN registry.gitlab.comtest:
stage: test
script:
- docker-compose run web python manage.py test --no-input
build:
stage: build
script:
- docker-compose build
- docker-compose push
tags:
- docker
deploy:
stage: deploy
script:
- docker stack deploy --compose-file docker-compose.yml stack-name
tags:
- docker
only:
- master