Skip to content
This repository has been archived by the owner on Jan 12, 2022. It is now read-only.

Systemd, ENV, latest stable Moodle #6

Merged
merged 17 commits into from
Aug 28, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

# Moodle version
MOODLE_DOWNLOAD_FILE=moodle-latest-35.tgz
MOODLE_TRACK=stable35
MOODLE_VERSION=3.5
ONELOGIN_PLUGIN_VER=v2.5.1
Expand All @@ -10,7 +11,11 @@ PHP_VERSION=7.2
# Nginx version
NGINX_VERSION=1.14.0-0+xenial1

# Docker
DOCKER_REGISTRY_URL=docker.sdelements.com:443/moodle

# Moodle variables
# WWWROOT MUST be IP or FQDN
MOODLE_WWWROOT=https://localhost
MOODLE_DATAROOT=/opt/moodle/moodledata
[email protected]
Expand Down
15 changes: 14 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,20 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [0.1.0] - 2017-08-13
## [0.1.1] - 2018-08-23
### Added
- `systemd` files to DEB package
- `docker-moodle` unit file
- `preinst` and `prerm` scripts
- Add configurable Docker registry URL

### Changed
- Build from the latest stable Moodle build
- Update DEB builder `README.md`
- Fetch images from Docker registry URL by default
- Update `README.md` with latest changes

## [0.1.0] - 2018-08-13
### Added
- Project `CHANGELOG.md`
- Container for building DEB packages
Expand Down
71 changes: 9 additions & 62 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,80 +3,30 @@
## Summary
This project deploys the Moodle (Modular Object-Oriented Dynamic Learning Environment) course management system using one Docker container that runs both Nginx and PHP/PHP-FPM services

## Setup
## Local Environment Setup

1. Install Docker on your system.
##### CentOS 7
```bash
# Optional
yum install -y yum-utils device-mapper-persistent-data lvm2

yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum install -y docker-ce
systemctl enable docker.service
systemctl start docker.service
systemctl status docker.service

yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
yum install -y python2-pip
pip install docker-compose
```

##### Ubuntu 16.04
```bash
# Remove the Kubernetes Apt source file in `/etc/apt/sources.list.d` or add the Apt key if you require it
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 6A030B21BA07F4FB

# Dependencies
apt-get update
apt-get install -y apt-transport-https ca-certificates curl software-properties-common

# Apt key
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
apt-key fingerprint 0EBFCD88

# Remove legacy docker, add repo, install latest docker
apt-get remove -y docker docker-engine docker.io
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
apt-get update
apt-get install -y docker-ce
systemctl enable docker.service
systemctl start docker.service
systemctl status docker.service

# Docker compose
curl -L https://github.com/docker/compose/releases/download/1.21.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
docker-compose --version
./setup.sh
```

2. Copy/clone dockerfiles from the `moodle-docker` repository and build the containers. Note: `docker-postgres` is a Git submodule in `moodle-docker`.
```bash
# Moodle repo
git clone [email protected].com:deployment/moodle-docker.git
git clone https://github.com/SecurityCompass/moodle-docker.git

# Pull submodules into local repo
git submodule update --init

# Postgres entrypoint has to be executable. Git holds the executable bit but sometimes the file is created with incorrect permissions.
chmod +x moodle-docker/docker-postgres/9.6/alpine/docker-entrypoint.sh
```

3. Copy your SSL certificate and key into the `conf/etc/nginx/ssl/` dir as `moodle.crt` and `moodle.key`. The included pair are self-signed and can be used (TESTING ONLY).

Instructions below to generate your own self-signed certificate pair.

4. Create data directory for Moodle (on the host VM)
```bash
mkdir -p /opt/moodle/moodledata
chmod 777 /opt/moodle/moodledata
```
4. Customize `.env` according to your environment. Most notably `MOODLE_WWWROOT` (based on your instance IP/FQDN)

5. Customize `.env` according to your environment. Most notably `MOODLE_VERSION` and `MOODLE_WWWROOT` (based on your instance IP/FQDN)

6. Build, configure and start the docker containers with docker-compose.
5. Build, configure and start the docker containers with docker-compose.
* `-d` toggles foreground/background
* `-V` recreates anonymous docker volumes (DATA LOSS!)

Here are some ways to run these containers:

Expand All @@ -89,31 +39,28 @@ This project deploys the Moodle (Modular Object-Oriented Dynamic Learning Enviro
##### Deploy locally (Full stack)
```bash
cd moodle-docker
docker-compose -f docker-compose.yml -f dc.local.yml up --force-recreate --always-recreate-deps -d -V
docker-compose -f docker-compose.yml -f dc.local.yml up --force-recreate --always-recreate-deps -d
```
* Nginx ports: `8443/8080`
* Postgres port: `N/A`

##### Deploy in production (Full stack)
```bash
cd moodle-docker
docker-compose -f docker-compose.yml -f dc.prod.yml up --force-recreate --always-recreate-deps -d -V
docker-compose -f docker-compose.yml -f dc.prod.yml up --force-recreate --always-recreate-deps -d
```
* Nginx ports: `443/80`
* Postgres port: `N/A`

##### Deploy Web server and DB separately (separate servers)
```bash
cd moodle-docker
docker-compose -f docker-compose.yml -f dc.prod-dbonly.yml up --force-recreate -d -V postgres
docker-compose -f docker-compose.yml -f dc.prod.yml up --force-recreate --no-deps -d -V nginx-php-moodle
docker-compose -f docker-compose.yml -f dc.prod-dbonly.yml up --force-recreate -d postgres
docker-compose -f docker-compose.yml -f dc.prod.yml up --force-recreate --no-deps -d nginx-php-moodle
```
* Nginx ports: `8443/8080`
* Postgres port: `5432`

7. Follow these instructions to setup the Moodle app:
https://securitycompass.atlassian.net/wiki/spaces/DEP/pages/204046339/Moodle+Docker+Deployment

## Misc.

* Generate self-signed certificate (TESTING ONLY)
Expand Down
1 change: 1 addition & 0 deletions dc.build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ services:
nginx-php-moodle:
build:
args:
MOODLE_DOWNLOAD_FILE: "${MOODLE_DOWNLOAD_FILE}"
MOODLE_TRACK: "${MOODLE_TRACK}"
MOODLE_VERSION: "${MOODLE_VERSION}"
NGINX_VERSION: "${NGINX_VERSION}"
Expand Down
16 changes: 12 additions & 4 deletions dc.deb.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ services:
#
- "--deb-field"
- "Vcs-Browser: https://github.com/SecurityCompass/moodle-docker"
#
- "--after-install"
- "/package/systemd/postinst.sh"
#
- "--before-remove"
- "/package/systemd/prerm.sh"
# Package dependencies
- "--depends"
- "docker-ce > 18"
Expand All @@ -58,10 +64,12 @@ services:
# Enables INFO output
- "--verbose"
# Files to package
- "/package/conf=/etc/moodle-docker"
- "/package/dc.prod.yml=/etc/moodle-docker"
- "/package/dc.prod-dbonly.yml=/etc/moodle-docker"
- "/package/docker-compose.yml=/etc/moodle-docker"
- "/package/.env=/etc/moodle-docker/"
- "/package/conf=/etc/moodle-docker/"
- "/package/dc.prod-dbonly.yml=/etc/moodle-docker/"
- "/package/dc.prod.yml=/etc/moodle-docker/"
- "/package/docker-compose.yml=/etc/moodle-docker/"
- "/package/systemd/moodle-docker.service=/lib/systemd/system/"
environment:
MOODLE_VERSION: "${MOODLE_VERSION}"
PHP_VERSION: "${PHP_VERSION}"
Expand Down
9 changes: 8 additions & 1 deletion deb-builder/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ moodle-docker_deb-build_1 exited with code 0
│   │   └── etc
│   │   ├── nginx
│   │   │   ├── conf.d
│   │   │   │   ├── moodle.conf
│   │   │   │   └── moodle.template
│   │   │   ├── nginx.conf
│   │   │   └── ssl
Expand All @@ -77,12 +78,18 @@ moodle-docker_deb-build_1 exited with code 0
│   ├── dc.prod-dbonly.yml
│   ├── dc.prod.yml
│   └── docker-compose.yml
├── lib
│   └── systemd
│   └── system
│   └── moodle-docker.service
├── md5sums
├── postinst
├── prerm
└── usr
└── share
└── doc
└── moodle-docker
└── changelog.gz

16 directories, 16 files
19 directories, 19 files
```
4 changes: 2 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ services:
nginx-php-moodle:
networks:
all:
image: nginx-php-moodle:${PHP_VERSION}-${MOODLE_VERSION}
image: ${DOCKER_REGISTRY_URL}/nginx-php-moodle:${PHP_VERSION}-${MOODLE_VERSION}
depends_on:
- postgres
environment:
Expand Down Expand Up @@ -57,7 +57,7 @@ services:
postgres:
networks:
all:
image: moodle-postgres
image: ${DOCKER_REGISTRY_URL}/postgres:9.6
environment:
POSTGRES_DB: "${PGSQL_DATABASE}"
POSTGRES_USER: "${PGSQL_USER}"
Expand Down
4 changes: 3 additions & 1 deletion nginx-php-moodle/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ FROM ubuntu:xenial
# Disable frontend dialogs
ENV DEBIAN_FRONTEND noninteractive

ARG MOODLE_DOWNLOAD_FILE
ARG MOODLE_TRACK
ARG MOODLE_VERSION
ARG NGINX_VERSION
Expand All @@ -11,6 +12,7 @@ ARG PHP_VERSION

# Print ARGs and install utility packages
RUN echo "Moodle track: $MOODLE_TRACK" \
&& echo "Moodle filename: ${MOODLE_DOWNLOAD_FILE}" \
&& echo "Moodle version: ${MOODLE_VERSION}" \
&& echo "Nginx version: ${NGINX_VERSION}" \
&& echo "OneLogin version: ${ONELOGIN_PLUGIN_VER}" \
Expand Down Expand Up @@ -66,7 +68,7 @@ RUN echo "Starting Moodle App install..." \
&& apt-get update \
&& apt-get install -y wget \
&& mkdir -v /opt/moodle \
&& wget -q https://download.moodle.org/download.php/direct/${MOODLE_TRACK}/moodle-${MOODLE_VERSION}.tgz -O /opt/moodle/moodle-${MOODLE_VERSION}.tgz \
&& wget -q https://download.moodle.org/download.php/direct/${MOODLE_TRACK}/${MOODLE_DOWNLOAD_FILE} -O /opt/moodle/moodle-${MOODLE_VERSION}.tgz \
&& tar -xzf /opt/moodle/moodle-${MOODLE_VERSION}.tgz -C /opt/moodle \
&& mv /opt/moodle/moodle /opt/moodle/moodle-${MOODLE_VERSION} \
&& rm /opt/moodle/moodle-${MOODLE_VERSION}.tgz \
Expand Down
21 changes: 21 additions & 0 deletions systemd/moodle-docker.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[Unit]
Description=Docker based Moodle Deployment
Documentation=https://github.com/SecurityCompass/moodle-docker
After=docker.service
Requires=docker.service

[Service]
WorkingDirectory=/etc/moodle-docker
Type=oneshot
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a oneshot service? generally that's used for scripts that exit, but this will remain running as a service.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

docker-compose doesn't stay running, the actual containers are managed by docker

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you remove the --detach it will stay running, that way the logs show up properly with journalctl.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--detach is safer in prod because it saves on resources.. plus we should have a proper logging solution vs docker -> docker-compose -> journalctl

Some more notes here:
docker/compose#4266 (comment)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, I would much rather we use the 'syslog' docker logging driver and leave compose detached. This is what I'm doing for SDE, and instead of dumping logs into the compose stdout, it will send them to syslog with an appropriate container tag. Let me know if you have questions about this.

Copy link
Contributor

@mroote mroote Aug 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What resources would it be using exactly? The example posted before that comment is the correct way to do this IMO. The proper logging solution is to use this as a simple service and not oneshot. If we send the logs to journald it's easy to then move them elsewhere to a centralized location.

What's the behaviour with stopping a container in a oneshot service? once docker-compose exits the oneshot service will report it's exited successfully. This could leave you in a weird state where the container is running/crashed but systemd is not aware of this.

Also what happens when docker-compose exits but the container stops right after due to an error or some other reason? In this case systemd wont print any errors and the oneshot service will report success even though the container is not running.

Another reason to make this a simple service would be then we can use the Restart and related config fields to ensure the container is brought back up if it exits for some reason.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed further with @hrpatel, I think we are good to go with the oneshot approach.

RemainAfterExit=yes

ExecStartPre=-/usr/local/bin/docker-compose --file /etc/moodle-docker/docker-compose.yml pull --quiet
ExecStart=/usr/local/bin/docker-compose --file /etc/moodle-docker/docker-compose.yml --file /etc/moodle-docker/dc.prod.yml up --detach
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the container is managed with systemd we don't want to detach from the container here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its cleaner to detach and let docker handle logs/output/etc.. and only use systemd to manage starting and stopping

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not keep it attached and let systemd handling the logging also? Then systemd can detect if the container crashes or stops for some reason. You will also be able to access the logs through docker but it's easier to use journalctl and get all logs at once.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The syslog logging driver should dump everything to a log file, but we could also try the journald logging driver instead: https://docs.docker.com/config/containers/logging/journald/#options


ExecReload=-/usr/local/bin/docker-compose --file /etc/moodle-docker/docker-compose.yml pull --quiet
ExecReload=/usr/local/bin/docker-compose --file /etc/moodle-docker/docker-compose.yml --file /etc/moodle-docker/dc.prod.yml up --detach

ExecStop=/usr/local/bin/docker-compose --file /etc/moodle-docker/docker-compose.yml stop

[Install]
WantedBy=multi-user.target
46 changes: 46 additions & 0 deletions systemd/postinst.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#!/bin/sh
after_upgrade() {
:

systemctl --system daemon-reload >/dev/null || true
if ! systemctl is-enabled moodle-docker >/dev/null
then
systemctl enable moodle-docker >/dev/null || true
systemctl start moodle-docker >/dev/null || true
else
systemctl restart moodle-docker >/dev/null || true
fi
}

after_install() {
:
#!/usr/bin/env bash

systemctl --system daemon-reload >/dev/null || true
systemctl enable moodle-docker >/dev/null || true
# Skip starting since we need to configure `.env`
#systemctl start moodle-docker >/dev/null || true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should remove this line if it's not needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to uncomment once I automate a couple more things:

  • populate hostname dynamically (if possible) or fail back to IP
    • still need to figure out a lets encrypt solution here
  • auto-generate random passwords for each field in .env

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah alright let's leave this part in for now then.

}

if [ "${1}" = "configure" ] && [ -z "${2}" ] || \
[ "${1}" = "abort-remove" ]
then
# "after install" here
# "abort-remove" happens when the pre-removal script failed.
# In that case, this script, which should be idemptoent, is run
# to ensure a clean roll-back of the removal.
after_install
elif [ "${1}" = "configure" ] && [ -n "${2}" ]
then
upgradeFromVersion="${2}"
# "after upgrade" here
# NOTE: This slot is also used when deb packages are removed,
# but their config files aren't, but a newer version of the
# package is installed later, called "Config-Files" state.
# basically, that still looks a _lot_ like an upgrade to me.
after_upgrade "${upgradeFromVersion}"
elif echo "${1}" | grep -E -q "(abort|fail)"
then
echo "Failed to install before the post-installation script was run." >&2
exit 1
fi
30 changes: 30 additions & 0 deletions systemd/prerm.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/bin/sh
before_remove() {
:

systemctl stop moodle-docker >/dev/null || true
systemctl disable moodle-docker >/dev/null || true
systemctl --system daemon-reload >/dev/null || true
}

dummy() {
:
}

if [ "${1}" = "remove" ] && [ -z "${2}" ]
then
# "before remove" goes here
before_remove
elif [ "${1}" = "upgrade" ]
then
# Executed before the old version is removed
# upon upgrade.
# We should generally not do anything here. The newly installed package
# should do the upgrade, not the uninstalled one, since it can't anticipate
# what new things it will have to do to upgrade for the new version.
dummy
elif echo "${1}" | grep -E -q "(fail|abort)"
then
echo "Failed to install before the pre-removal script was run." >&2
exit 1
fi