First version
This commit is contained in:
		
							
								
								
									
										25
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								Dockerfile
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										66
									
								
								README.md
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										104
									
								
								docker-hook
									
									
									
									
									
										Executable 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
									
								
							
							
						
						
									
										8
									
								
								entrypoint.sh
									
									
									
									
									
										Executable 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
									
								
							
							
						
						
									
										25
									
								
								nginx.conf
									
									
									
									
									
										Normal 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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user