First version

This commit is contained in:
Yohann D'ANELLO 2020-11-22 22:57:24 +01:00
commit e3e32d4046
6 changed files with 234 additions and 0 deletions

25
Dockerfile Normal file
View File

@ -0,0 +1,25 @@
FROM python:3-alpine
RUN apk --update add git nginx && \
rm /var/cache/apk/*
RUN pip install requests --no-cache-dir
RUN mkdir /hook
RUN mkdir -p /var/www/html
# Configure nginx
RUN mkdir /run/nginx
RUN ln -sf /dev/stdout /var/log/nginx/access.log && ln -sf /dev/stderr /var/log/nginx/error.log
COPY nginx.conf /etc/nginx/conf.d/mkdocs-server.conf
RUN rm /etc/nginx/conf.d/default.conf
COPY ./entrypoint.sh /hook
COPY ./docker-hook /hook
COPY ./update.sh /hook
WORKDIR /var/www/html
ENTRYPOINT ["/hook/entrypoint.sh"]
EXPOSE 80

66
README.md Normal file
View File

@ -0,0 +1,66 @@
# Serveur Nginx statique auto-mis à jour via Git
Cette image Docker permet la mise en place d'un serveur Nginx dont les sources sont un
site statique.
Cependant, cette image offre l'avantage de mettre à jour automatiquement le site dès lors
que la branche `master` du dépôt Git est modifiée.
## Configuration
On désignera par `www.exemple.com` le site sur lequel vous souhaitez héberger votre site.
Sur votre dépôt Git, ajoutez un nouveau webhook déclenché à chaque événement `push`
(cela suffit normalement) vers l'adresse `https://www.exemple.com/trigger-ci.json`.
Il vous suffit ensuite de lancer l'image Docker en renseignant la variable d'environnement
`MKDOCS_SERVER_GIT_URL` par l'adresse de clonage **HTTPS** du dépôt Git. Par exemple, pour
ce dépôt, il s'agit de l'adresse `https://gitlab.com/animath/si/mkdocs-server-from-git.git`.
Un exemple :
```bash
docker run -e NGINX_SERVER_GIT_URL=https://gitlab.com/me/mon-super-projet-nginx.git -p 8000:80 ynerant/nginx-server-from-git
```
Le résultat s'observe sur `http://localhost:8000`.
Il est recommandé d'utiliser `docker-compose` :
```yaml
nginx-static-server:
image: ynerant/nginx-server-from-git
ports:
- 8000:80
environment:
- NGINX_SERVER_GIT_URL=https://gitlab.com/me/mon-super-projet.git
```
Si vous utilisez Traefik comme reverse-proxy :
```yaml
nginx-static-server:
image: ynerant/nginx-server-from-git
restart: always
environment:
- NGINX_SERVER_GIT_URL=https://gitlab.com/me/mon-super-projet.git
labels:
- "traefik.enable=true"
- "traefik.http.routers.nginx-static-server.rule=Host(`www.exemple.com`)"
- "traefik.http.routers.nginx-static-server.entrypoints=websecure"
- "traefik.http.routers.nginx-static-server.tls.certresolver=mytlschallenge"
```
À vous bien sûr d'adapter la configuration comme bon vous semble.
Enjoy :)
## Fonctionnement
L'image contient un serveur Nginx avec deux entrées : un serveur classique desservant
le dossier `/var/www/html` et une entrée écoutant sur `/trigger-ci.json` écrite en Python
afin de récupérer l'événement de `push` envoyé par le serveur Git.
À chaque push, le script `update.sh` est exécuté, visant simplement à effectuer un
`git pull` afin de mettre à jour les fichiers.
Le dossier `.git` n'est pas desservi pour des raisons de sécurité.

104
docker-hook Executable file
View File

@ -0,0 +1,104 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
"""Automatic Docker Deployment via Webhooks."""
import json
import os
from subprocess import Popen
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
from http.server import HTTPServer
from http.server import BaseHTTPRequestHandler
import sys
import logging
import requests
logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s',
level=logging.DEBUG,
stream=sys.stdout)
class RequestHandler(BaseHTTPRequestHandler):
"""A POST request handler which expects a token in its path."""
def do_POST(self):
try:
logging.info("Path: %s", self.path)
header_length = int(self.headers.get('content-length', "0"))
json_payload = self.rfile.read(header_length)
env = dict(os.environ)
json_params = {}
if len(json_payload) > 0:
json_params = json.loads(json_payload)
env.update(('REPOSITORY_' + var.upper(), str(val))
for var, val in json_params['repository'].items())
logging.info("Start executing '%s'" % args.cmd)
try:
Popen(args.cmd, env=env).wait()
self.send_response(200, "OK")
if 'callback_url' in json_params:
# Make a callback to Docker Hub
data = {'state': 'success'}
headers = {'Content-type': 'application/json',
'Accept': 'text/plain'}
requests.post(json_params['callback_url'],
data=json.dumps(data),
headers=headers)
except OSError as err:
self.send_response(500, "OSError")
logging.error("You probably didn't use 'sh ./script.sh'.")
logging.error(err)
if 'callback_url' in json_params:
# Make a callback to Docker Hub
data = {'state': 'failure',
'description': str(err)}
headers = {'Content-type': 'application/json',
'Accept': 'text/plain'}
requests.post(json_params['callback_url'],
data=json.dumps(data),
headers=headers)
self.end_headers()
except Exception as e:
logging.error(e)
def get_parser():
"""Get a command line parser for docker-hook."""
parser = ArgumentParser(description=__doc__,
formatter_class=ArgumentDefaultsHelpFormatter)
parser.add_argument("-t", "--token",
dest="token",
required=False,
help=("Secure auth token (can be choosen "
"arbitrarily)"))
parser.add_argument("-c", "--cmd",
dest="cmd",
required=True,
nargs="*",
help="Command to execute when triggered")
parser.add_argument("--addr",
dest="addr",
default="0.0.0.0",
help="address where it listens")
parser.add_argument("--port",
dest="port",
type=int,
default=8555,
metavar="PORT",
help="port where it listens")
return parser
def main(addr, port):
"""Start a HTTPServer which waits for requests."""
httpd = HTTPServer((addr, port), RequestHandler)
httpd.serve_forever()
if __name__ == '__main__':
parser = get_parser()
if len(sys.argv) == 1:
parser.print_help()
sys.exit(1)
args = parser.parse_args()
main(args.addr, args.port)

8
entrypoint.sh Executable file
View File

@ -0,0 +1,8 @@
#!/bin/sh
cd /var/www/html
[ -d .git ] || git clone ${NGINX_SERVER_GIT_URL} .
git pull
nginx&
python /hook/docker-hook -c sh /hook/update.sh

25
nginx.conf Normal file
View File

@ -0,0 +1,25 @@
upstream trigger-ci {
server 127.0.0.1:8555;
}
server {
listen 80;
server_name static-server;
root /var/www/html;
error_page 404 /404.html;
location /trigger-ci.json {
proxy_pass http://trigger-ci;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_redirect off;
}
location /.git* {
return 404;
}
location /README* {
return 404;
}
}

6
update.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/sh
old_pwd=$PWD
cd /var/www/html
git pull
export PWD=old_pwd