1
0
mirror of https://github.com/balkian/lab-in-a-box.git synced 2025-08-29 16:52:21 +00:00

First commit

This commit is contained in:
J. Fernando Sánchez
2018-05-20 20:14:00 +02:00
commit 3f287c88b3
11 changed files with 535 additions and 0 deletions

View File

@@ -0,0 +1,51 @@
This deployment contains:
* Gitlab for code and authentication. The omnibus image is an all-in-one package that contains:
* Git (`git.domain.com`) and CI/CD
* Docker registry (`registry.domain.com`)
* Mattermost (slack clone, `chat.domain.com`)
* Postgres db
* Jupyterhub for multi-user computing (`hub.domain.com`)
* Authentication with Gitlab
* Every user has an isolated environment (thanks to Docker-spawner)
* Based on https://github.com/balkian/jupyterhub-oauth
* Nginx as a reverse proxy
# Instructions
Set the `DOMAIN` variable in a `.env` file and run this compose.
After GitLab is loaded, create an OAuth application in Gitlab: https://docs.gitlab.com/ce/integration/oauth_provider.html
The redirect URL is: `https://hub.<your domain>/hub/oauth_callback`.
Click on `API` level and `trusted`.
Write the client ID and client secret to a `.env` file in this folder.
Then, update the Jupyter service.
# Example .env file
```
DOMAIN=<YOUR DOMAIN>
GITLAB_CLIENT_ID=<YOUR ID>
GITLAB_CLIENT_SECRET=<YOUR SECRET>
```
# Advanced configuration
GitLab's documentation is terrific.
For a list of configuration options, see https://docs.gitlab.com/omnibus/docker/#install-gitlab-using-docker-compose .
# Note
When run as part of the omnibus, mattermost should register an application automatically on Gitlab.
I've had some issues with authentication, so if I've explicitly added the OAuth parameters in the compose file.
This way, you can manually register mattermost on your instance.
The process is similar to jupyter, and the callback URLs are:
```
https://chat.$DOMAIN/signup/gitlab/complete
https://chat.$DOMAIN/login/gitlab/complete
```

View File

@@ -0,0 +1,118 @@
version: '3.6'
services:
web:
build: nginx
networks:
- labinabox
image: 'custom-nginx'
depends_on:
- jupyter
- gitlab
ports:
- '80:80'
- '443:443'
environment:
REGISTRY_INTERNAL: http://gitlab:4567
LAB_INTERNAL: http://gitlab:80
HUB_INTERNAL: http://jupyter:8000
DOMAIN: ${DOMAIN-?todevnull.com}
volumes:
- '/etc/ssl/ssl-custom/cert.pem:/ssl/certs/nginx.crt'
- '/etc/ssl/ssl-custom/key.pem:/ssl/private/nginx.key'
- '/data/html:/usr/share/nginx/html'
gitlab:
networks:
- labinabox
image: 'gitlab/gitlab-ce:10.7.3-ce.0'
restart: always
hostname: 'lab.${DOMAIN-?todevnull.com}'
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'https://lab.${DOMAIN-?todevnull.com}'
mattermost_external_url 'https://chat.todevnull.com/'
registry_external_url 'https://registry.${DOMAIN-?todevnull.com}'
nginx['listen_port'] = 80
nginx['listen_https'] = false
# LFS
gitlab_rails['lfs_enabled'] = true
gitlab_rails['lfs_storage_path'] = "/mnt/lfs"
# Registry
gitlab_rails['registry_enabled'] = true
gitlab_rails['registry_port'] = "443"
registry_nginx['redirect_http_to_https'] = false
registry_nginx['listen_port'] = 4567
registry_nginx['nginx_enable'] = true
registry_nginx['listen_https'] = false
registry_nginx['https'] = false
gitlab_rails['registry_api_url'] = "http://127.0.0.1:5000"
registry['registry_http_addr'] = "127.0.0.1:5000"
registry_nginx['proxy_set_headers'] = {
"Host" => "registry.${DOMAIN}",
"X-Forwarded-Proto" => "https",
"X-Forwarded-Ssl" => "on"
}
mattermost['service_use_ssl'] = false
mattermost_nginx['listen_port'] = 80
mattermost_nginx['listen_https'] = false
mattermost['gitlab_enable'] = true
mattermost['gitlab_id'] = "${MATTERMOST_ID}"
mattermost['gitlab_secret'] = "${MATTERMOST_SECRET}"
mattermost['gitlab_scope'] = ""
mattermost['gitlab_auth_endpoint'] = "https://lab.${DOMAIN-?todevnull.com}/oauth/authorize"
mattermost['gitlab_token_endpoint'] = "https://lab.${DOMAIN-?todevnull.com}/oauth/token"
mattermost['gitlab_user_api_endpoint'] = "https://lab.${DOMAIN-?todevnull.com}/api/v4/user"
# Chat
mattermost_nginx['redirect_http_to_https'] = false
ports:
- '8080:80'
- '8443:443'
- '22:22'
- '4567:4567'
volumes:
- 'gitlab-config:/etc/gitlab'
- 'gitlab-logs:/var/log/gitlab'
- 'gitlab-data:/var/opt/gitlab'
- 'gitlab-lfs:/mnt/lfs'
jupyter:
networks:
- labinabox
image: gsiupm/jupyterhub-oauth:0.8.1
command: jupyterhub --no-ssl -f /srv/jupyterhub/jupyterhub_config.py
hostname: jupyterhub
volumes:
- "/mnt/home:/mnt/home"
- "/var/run/docker.sock:/var/run/docker.sock"
environment:
OAUTH_CALLBACK_URL: "https://hub.${DOMAIN-?todevnull.com}/hub/oauth_callback"
HOST_HOMEDIR: "/mnt/home/{username}"
OAUTH_CLASS: "oauthenticator.gitlab.GitLabOAuthenticator"
GITLAB_HOST: "https://lab.${DOMAIN-?todevnull.com}/"
GITLAB_CLIENT_ID: "${GITLAB_CLIENT_ID}"
GITLAB_CLIENT_SECRET: "${GITLAB_CLIENT_SECRET}"
JPY_COOKIE_SECRET: "${JPY_COOKIE_SECRET}"
JPY_API_TOKEN: "${CONFIGPROXY_AUTH_TOKEN}"
OAUTH_TLS_VERIFY: 0
COMMON_DIR: "/mnt/home/common"
DATASETS_DIR: "/mnt/home/datasets"
ADMINS: "${HUB_ADMINS-balkian,root}"
DOCKER_NETWORK: labinabox
DOCKER_MEM_LIMIT: '150M'
volumes:
gitlab-config:
name: gitlab-config
gitlab-logs:
name: gitlab-logs
gitlab-data:
name: gitlab-data
gitlab-lfs:
name: gitlab-lfs
networks:
labinabox:
name: labinabox

View File

@@ -0,0 +1,9 @@
FROM nginx:1.13
ENV DOMAIN="todevnull.com" HUB_INTERNAL="http://jupyter:80" LAB_INTERNAL="gitlab:80" REGISTRY_INTERNAL="gitlab:5000"
COPY init.sh /
COPY snippets/ /etc/nginx/snippets/
COPY conf.d /etc/nginx/conf.d/
CMD /init.sh

View File

@@ -0,0 +1,54 @@
server {
listen 80;
access_log /var/log/nginx/hub.access.log;
# add Strict-Transport-Security to prevent man in the middle attacks
server_name hub.${DOMAIN};
root /var/www/html/ ;
include /etc/nginx/snippets/letsencrypt.conf;
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name hub.${DOMAIN} ;
access_log /var/log/nginx/hub.access.log;
error_log /var/log/nginx/hub.error.log;
# add Strict-Transport-Security to prevent man in the middle attacks
#add_header Strict-Transport-Security "max-age=31536000";
client_max_body_size 100M;
ssl_certificate /ssl/certs/nginx.crt;
ssl_certificate_key /ssl/private/nginx.key;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass ${HUB_INTERNAL};
}
location ~* /user/([a-zA-Z0-9]+)/(api/kernels/[^/]+/(channels|iopub|shell|stdin)|terminals/websocket)/? {
proxy_set_header Host $host;
# websocket support
proxy_http_version 1.1;
proxy_set_header Upgrade "websocket";
proxy_set_header Connection "Upgrade";
proxy_pass ${HUB_INTERNAL};
}
}

View File

@@ -0,0 +1,79 @@
server {
listen 80;
server_name lab.${DOMAIN} chat.${DOMAIN};
root /var/www/html/ ;
include /etc/nginx/snippets/letsencrypt.conf;
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name lab.${DOMAIN} chat.${DOMAIN} ;
access_log /var/log/nginx/gitlab.access.log;
error_log /var/log/nginx/gitlab.error.log;
# add Strict-Transport-Security to prevent man in the middle attacks
#add_header Strict-Transport-Security "max-age=31536000";
ssl_certificate /ssl/certs/nginx.crt;
ssl_certificate_key /ssl/private/nginx.key;
root /var/www/html/ ;
location / {
client_max_body_size 0;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass ${LAB_INTERNAL} ;
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name registry.${DOMAIN} ;
access_log /var/log/nginx/gitlab-registry.access.log;
error_log /var/log/nginx/gitlab-registry.error.log;
# add Strict-Transport-Security to prevent man in the middle attacks
#add_header Strict-Transport-Security "max-age=31536000";
# disable any limits to avoid HTTP 413 for large image uploads
client_max_body_size 0;
# required to avoid HTTP 411: see Issue #1486 (https://github.com/docker/docker/issues/1486)
chunked_transfer_encoding on;
ssl_protocols TLSv1.1 TLSv1.2;
ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
include /etc/nginx/snippets/letsencrypt.conf;
root /var/www/html/ ;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass ${REGISTRY_INTERNAL};
proxy_read_timeout 900;
}
}

View File

@@ -0,0 +1,9 @@
#!/bin/sh
cd /etc/nginx/conf.d/
VARIABLES='${HUB_INTERNAL}${DOMAIN}${LAB_INTERNAL}${REGISTRY_INTERNAL}'
for i in *.template; do
target=$(basename $i ".template")
envsubst $VARIABLES < $i > $target;
done || exit 1
nginx -g 'daemon off;'

View File

@@ -0,0 +1,44 @@
#############################################################################
# Configuration file for Let's Encrypt ACME Challenge location
# This file is already included in listen_xxx.conf files.
# Do NOT include it separately!
#############################################################################
#
# This config enables to access /.well-known/acme-challenge/xxxxxxxxxxx
# on all our sites (HTTP), including all subdomains.
# This is required by ACME Challenge (webroot authentication).
# You can check that this location is working by placing ping.txt here:
# /var/www/letsencrypt/.well-known/acme-challenge/ping.txt
# And pointing your browser to:
# http://xxx.domain.tld/.well-known/acme-challenge/ping.txt
#
# Sources:
# https://community.letsencrypt.org/t/howto-easy-cert-generation-and-renewal-with-nginx/3491
#
#############################################################################
# Rule for legitimate ACME Challenge requests (like /.well-known/acme-challenge/xxxxxxxxx)
# We use ^~ here, so that we don't check other regexes (for speed-up). We actually MUST cancel
# other regex checks, because in our other config files have regex rule that denies access to files with dotted names.
location ^~ /.well-known/acme-challenge/ {
# Set correct content type. According to this:
# https://community.letsencrypt.org/t/using-the-webroot-domain-verification-method/1445/29
# Current specification requires "text/plain" or no content header at all.
# It seems that "text/plain" is a safe option.
default_type "text/plain";
# This directory must be the same as in /etc/letsencrypt/cli.ini
# as "webroot-path" parameter. Also don't forget to set "authenticator" parameter
# there to "webroot".
# Do NOT use alias, use root! Target directory is located here:
# /var/www/common/letsencrypt/.well-known/acme-challenge/
root /var/www/letsencrypt;
}
# Hide /acme-challenge subdirectory and return 404 on all requests.
# It is somewhat more secure than letting Nginx return 403.
# Ending slash is important!
location = /.well-known/acme-challenge/ {
return 404;
}