Skip to content

Commit

Permalink
Merge pull request #33 from markdumay/develop
Browse files Browse the repository at this point in the history
Bridge networking
  • Loading branch information
markdumay authored Nov 16, 2020
2 parents f96c904 + 6f6aba7 commit b9a15fa
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 37 deletions.
43 changes: 23 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,40 +80,44 @@ sudo ./syno_docker_update.sh [OPTIONS] COMMAND

| Command | Argument | Description |
|----------------|-----------|-------------|
| **`backup`** | | Create a backup of Docker binaries (including Docker Compose) and `dockerd` configuration |
| **`backup`** | | Create a backup of Docker binaries (including Docker Compose), `dockerd` configuration, and Synology's `start-stop-status` script |
| **`download`** | PATH | Download Docker and Docker Compose binaries to *PATH* |
| **`install`** | PATH | Update Docker and Docker Compose from files on *PATH* |
| **`restore`** | | Restore Docker and Docker Compose from a backup |
| **`update`** | | Update Docker and Docker Compose to a target version (creates a backup first) |

Under the hood, the five different commands invoke a specific workflow or sequence of steps. The below table shows the workflows and the order of steps for each of the commands.
| # | Workflow step | backup | download | install | restore | update |
|----|-----------------------------|--------|----------|---------|---------|--------|
| A) | Download Docker binary | | Step 1 | | | Step 1 |
| B) | Download Compose binary | | Step 2 | | | Step 2 |
| C) | Extract files from backup | | | | Step 1 | |
| D) | Stop Docker daemon | Step 1 | | Step 1 | Step 2 | Step 3 |
| E) | Backup current files | Step 2 | | Step 2 | | Step 4 |
| F) | Extract downloaded binaries | | | Step 3 | | Step 5 |
| G) | Restore Docker binaries | | | | Step 3 | |
| H) | Install Docker binaries | | | Step 4 | | Step 6 |
| I) | Update log driver | | | Step 5 | | Step 7 |
| J) | Restore log driver | | | | Step 4 | |
| K) | Start Docker daemon | Step 3 | | Step 6 | Step 5 | Step 8 |
| L) | Clean temp folder | | | | | Step 9 |
| # | Workflow step | backup | download | install | restore | update |
|----|-----------------------------|--------|----------|---------|---------|---------|
| A) | Download Docker binary | | Step 1 | | | Step 1 |
| B) | Download Compose binary | | Step 2 | | | Step 2 |
| C) | Extract files from backup | | | | Step 1 | |
| D) | Stop Docker daemon | Step 1 | | Step 1 | Step 2 | Step 3 |
| E) | Backup current files | Step 2 | | Step 2 | | Step 4 |
| F) | Extract downloaded binaries | | | Step 3 | | Step 5 |
| G) | Restore Docker binaries | | | | Step 3 | |
| H) | Install Docker binaries | | | Step 4 | | Step 6 |
| I) | Update log driver | | | Step 5 | | Step 7 |
| J) | Restore log driver | | | | Step 4 | |
| K) | Update Docker script | | | Step 5 | | Step 8 |
| L) | Restore Docker script | | | | Step 5 | |
| M) | Start Docker daemon | Step 3 | | Step 6 | Step 6 | Step 9 |
| N) | Clean temp folder | | | | | Step 10 |

* **A) Download Docker binary** - Downloads an archive containing Docker Engine binaries from `https://download.docker.com/linux/static/stable/x86_64/docker-${VERSION}.tgz`. The binaries are compatible with the Intel x86 (64 bit) architecture. Unless a specific version is specified by the `--docker` flag, *Synology-Docker` pulls the latest stable version available.
* **B) Download Compose binary** - Downloads the Docker Compose binary from `https://github.com/docker/compose/releases/download/${VERSION}/docker-compose-Linux-x86_64`. Unless a specific version is specified by the `--compose` flag, *Synology-Docker* pulls the latest stable version available.
* **C) Extract files from backup** - Extracts the files from a backup archive specified by the `--backup` flag to the temp directory (`/tmp/docker_update`).
* **D) Stop Docker daemon** - Stops the Docker daemon by invoking `synoservicectl --stop pkgctl-Docker`.
* **E) Backup current files** - Creates a backup of the current Docker binaries, including Docker Compose. The configuration of the logging driver is included in the archive too. The files included refer to `/var/packages/Docker/target/usr/bin/*` and `/var/packages/Docker/etc/dockerd.json`.
* **E) Backup current files** - Creates a backup of the current Docker binaries, including Docker Compose. The configuration of the logging driver and Synology's `start-stop-status` script are included in the archive too. The files included refer to `/var/packages/Docker/target/usr/bin/*`, `/var/packages/Docker/etc/dockerd.json`, and `/var/packages/Docker/scripts/start-stop-status`.
* **F) Extract downloaded binaries** - Extracts the files from a downloaded archive to the temp directory (`/tmp/docker_update`).
* **G) Restore Docker binaries** - Restores the Docker binaries in `/var/packages/Docker/target/usr/bin/*` with the binaries extracted from a backup archive.
* **H) Install Docker binaries** - Installs downloaded and extracted Docker binaries (including Docker Compose) to the folder `/var/packages/Docker/target/usr/bin/`.
* **I) Update log driver** - Replaces Synology's log driver with a default log driver `json-file` to improve compatibility. The configuration is updated at `/var/packages/Docker/etc/dockerd.json`
* **J) Restore log driver** - Restores the log driver (`/var/packages/Docker/etc/dockerd.json`) from the configuration within a backup archive.
* **K) Start Docker daemon** - Starts the Docker daemon by invoking `synoservicectl --start pkgctl-Docker`.
* **L) Clean temp folder** - Removes files from the temp directory (`/tmp/docker_update`). The temporary files are created when extracting a downloaded archive or extracting a backup.
* **K) Update Docker script** - Updates Synology's `start-stop-status` script for Docker to enable IP forwarding. This ensures containers can be properly reached in bridge networking mode. The script is updated at the location `/var/packages/Docker/scripts/start-stop-status`.
* **L) Restore Docker script** - Restores the `start-stop-status` script (`/var/packages/Docker/scripts/start-stop-status`) from the file within a backup archive.
* **M) Start Docker daemon** - Starts the Docker daemon by invoking `synoservicectl --start pkgctl-Docker`.
* **N) Clean temp folder** - Removes files from the temp directory (`/tmp/docker_update`). The temporary files are created when extracting a downloaded archive or extracting a backup.


### Options
Expand All @@ -132,9 +136,8 @@ Under the hood, the five different commands invoke a specific workflow or sequen
Using *Synology-Docker* to update your Synology Docker package is known to bring a few issues. They are listed below, including their workaround if available.

* **Containers cannot be launched via Docker UI** (see [issue #21][issue_launch]) - The Synology Docker package comes with a user interface (UI) to monitor and launch containers. Unfortunately, the launching of containers via the UI no longer works after having upgraded Docker with *Synology-Docker*. This could be caused by the specific Docker logging driver of Synology. Launching containers from the command line (via either Docker or Docker Compose) still works. [Portainer][portainer] could also be an alternative, but has not been tested by the author yet.
* **Containers cannot be reached in bridge mode** (see [issue #12][issue_bridge]) - Setting up Docker on your Synology with the synology-docker script might result in difficulty connecting with containers in bridge mode. Potential workarounds are to deploy your services in a Docker stack, or to setup a [macvlan][macvlan] network.
* **The update is incompatible with BTRFS volumes** (see [isse #22][issue_btrfs]) - Launching containers could result in an error `Failed to create btrfs snapshot: inappropriate ioctl for device` on volumes formatted with BTRFS. No workaround is available yet.
* **Docker service can be prevented to shut down properly** (see [issue #20][issue_timeout]) - The `synoservicectl` daemon does not always terminate as expected, possibly due to a conflict with Docker's live restore functionality. Home Assistant is a known example to use live restore. Manually shutting down the container(s) will ensure *Synology-Docker* runs correctly.
* **Docker service can be prevented from shutting down properly** (see [issue #20][issue_timeout]) - The `synoservicectl` daemon does not always terminate as expected, possibly due to a conflict with Docker's live restore functionality. Home Assistant is a known example to use live restore. Manually shutting down the container(s) will ensure *Synology-Docker* runs correctly.


## Contributing
Expand Down
84 changes: 67 additions & 17 deletions syno_docker_update.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
# Title : syno_docker_update.sh
# Description : An Unofficial Script to Update or Restore Docker Engine and Docker Compose on Synology
# Author : Mark Dumay
# Date : November 5th, 2020
# Version : 1.1.2
# Date : November 16th, 2020
# Version : 1.2.0
# Usage : sudo ./syno_docker_update.sh [OPTIONS] COMMAND
# Repository : https://github.com/markdumay/synology-docker.git
# License : MIT - https://github.com/markdumay/synology-docker/blob/master/LICENSE
Expand All @@ -24,21 +24,24 @@ readonly DEFAULT_DOCKER_VERSION='19.03.13'
readonly DEFAULT_COMPOSE_VERSION='1.27.4'
readonly CPU_ARCH='x86_64'
readonly DOWNLOAD_DOCKER="https://download.docker.com/linux/static/stable/${CPU_ARCH}"
readonly DOWNLOAD_GITHUB=https://github.com/docker/compose
readonly GITHUB_API_COMPOSE=https://api.github.com/repos/docker/compose/releases/latest
readonly SYNO_DOCKER_SERV_NAME=pkgctl-Docker
readonly DOWNLOAD_GITHUB='https://github.com/docker/compose'
readonly GITHUB_API_COMPOSE='https://api.github.com/repos/docker/compose/releases/latest'
readonly SYNO_DOCKER_SERV_NAME='pkgctl-Docker'
readonly SYNO_SERVICE_TIMEOUT='5m'
readonly SYNO_DOCKER_DIR=/var/packages/Docker
readonly SYNO_DOCKER_BIN_PATH=$SYNO_DOCKER_DIR/target/usr
readonly SYNO_DOCKER_BIN=$SYNO_DOCKER_BIN_PATH/bin
readonly SYNO_DOCKER_JSON_PATH=$SYNO_DOCKER_DIR/etc
readonly SYNO_DOCKER_JSON=$SYNO_DOCKER_JSON_PATH/dockerd.json
readonly SYNO_DOCKER_DIR='/var/packages/Docker'
readonly SYNO_DOCKER_BIN_PATH="${SYNO_DOCKER_DIR}/target/usr"
readonly SYNO_DOCKER_BIN="${SYNO_DOCKER_BIN_PATH}/bin"
readonly SYNO_DOCKER_SCRIPT_PATH="${SYNO_DOCKER_DIR}/scripts"
readonly SYNO_DOCKER_SCRIPT="${SYNO_DOCKER_SCRIPT_PATH}/start-stop-status"
readonly SYNO_DOCKER_JSON_PATH="${SYNO_DOCKER_DIR}/etc"
readonly SYNO_DOCKER_JSON="${SYNO_DOCKER_JSON_PATH}/dockerd.json"
readonly SYNO_DOCKER_JSON_CONFIG="{
\"data-root\" : \"$SYNO_DOCKER_DIR/target/docker\",
\"log-driver\" : \"json-file\",
\"registry-mirrors\" : [],
\"group\": \"administrators\"
}"
readonly SYNO_DOCKER_SCRIPT_FORWARDING='# ensure IP forwarding\n\t\tsudo iptables -P FORWARD ACCEPT\n'


#======================================================================================================================
Expand Down Expand Up @@ -545,7 +548,7 @@ execute_stop_syno() {
if [ "${stage}" = 'false' ] ; then
syno_status=$(synoservicectl --status "${SYNO_DOCKER_SERV_NAME}" | grep running -o)
if [ "${syno_status}" = 'running' ] ; then
timeout "${SYNO_SERVICE_TIMEOUT}" synoservicectl --stop "${SYNO_DOCKER_SERV_NAME}"
timeout --foreground "${SYNO_SERVICE_TIMEOUT}" synoservicectl --stop "${SYNO_DOCKER_SERV_NAME}"
syno_status=$(synoservicectl --status "${SYNO_DOCKER_SERV_NAME}" | grep stop -o)
if [ "${syno_status}" != 'stop' ] ; then
terminate "Could not stop Docker daemon"
Expand All @@ -557,7 +560,8 @@ execute_stop_syno() {
}

#======================================================================================================================
# Creates a backup of the current Docker binaries (including Docker Compose) and Docker daemon configuration.
# Creates a backup of the current Docker binaries (including Docker Compose), Docker daemon configuration, and
# the 'start-stop-status' script.
#======================================================================================================================
# Globals:
# - backup_dir
Expand All @@ -568,7 +572,8 @@ execute_stop_syno() {
execute_backup() {
print_status "Backing up current Docker binaries (${backup_dir}/${docker_backup_filename})"
cd "${backup_dir}" || terminate "Backup directory does not exist"
tar -czvf "${docker_backup_filename}" -C "$SYNO_DOCKER_BIN_PATH" bin -C "$SYNO_DOCKER_JSON_PATH" "dockerd.json"
tar -czvf "${docker_backup_filename}" -C "$SYNO_DOCKER_BIN_PATH" bin -C "$SYNO_DOCKER_JSON_PATH" "dockerd.json" \
-C "${SYNO_DOCKER_SCRIPT_PATH}" "start-stop-status"
if [ ! -f "${docker_backup_filename}" ] ; then
terminate "Backup issue"
fi
Expand Down Expand Up @@ -700,7 +705,9 @@ execute_install_bin() {
if [ "${skip_compose_update}" = 'false' ] ; then
cp "${download_dir}"/docker-compose "${SYNO_DOCKER_BIN}"/docker-compose
fi
chown root:root "${SYNO_DOCKER_BIN}"/*
chmod +x "${SYNO_DOCKER_BIN}"/*
mkdir -p /var/lib/docker/volumes # creates folder to improve compatability for some containers
else
echo "Skipping installation in STAGE mode"
fi
Expand All @@ -719,6 +726,7 @@ execute_restore_bin() {
print_status "Restoring binaries"
if [ "${stage}" = 'false' ] ; then
cp "${temp_dir}"/docker/* "${SYNO_DOCKER_BIN}"/
chown root:root "${SYNO_DOCKER_BIN}"/*
chmod +x "${SYNO_DOCKER_BIN}"/*
else
echo "Skipping restore in STAGE mode"
Expand Down Expand Up @@ -746,6 +754,27 @@ execute_update_log() {
fi
}

#======================================================================================================================
# Updates Synology's start-stop-status script for Docker to ensure IP forwarding is enabled, unless 'stage' is set to
# true.
#======================================================================================================================
# Globals:
# - stage
# Outputs:
# Updated start-stop-status script.
#======================================================================================================================
execute_update_script() {
print_status "Enabling IP forwarding"
if [ "${stage}" = 'false' ] ; then
if ! grep -q 'iptables -P FORWARD ACCEPT' "${SYNO_DOCKER_SCRIPT}"; then
match='# start docker'
sed -i "s/${match}/${SYNO_DOCKER_SCRIPT_FORWARDING}\n\t\t${match}/" "${SYNO_DOCKER_SCRIPT}"
fi
else
echo "Skipping configuration in STAGE mode"
fi
}

#======================================================================================================================
# Restores the Docker daemon log driver extracted from a backup archive, unless 'stage' is set to true.
#======================================================================================================================
Expand All @@ -764,6 +793,24 @@ execute_restore_log() {
fi
}

#======================================================================================================================
# Restores Synology's Docker start-stop-status script from a backup archive, unless 'stage' is set to true.
#======================================================================================================================
# Globals:
# - stage
# - temp_dir
# Outputs:
# Updated start-stop-status script.
#======================================================================================================================
execute_restore_script() {
print_status "Restoring start-stop-status script"
if [ "${stage}" = 'false' ] ; then
cp "${temp_dir}"/start-stop-status "${SYNO_DOCKER_SCRIPT}"
else
echo "Skipping restoring in STAGE mode"
fi
}

#======================================================================================================================
# Start the Docker daemon by invoking 'synoservicectl', unless 'stage' is set to true.
#======================================================================================================================
Expand All @@ -777,7 +824,7 @@ execute_start_syno() {
print_status "Starting Docker service"

if [ "${stage}" = 'false' ] ; then
timeout "${SYNO_SERVICE_TIMEOUT}" synoservicectl --start "${SYNO_DOCKER_SERV_NAME}"
timeout --foreground "${SYNO_SERVICE_TIMEOUT}" synoservicectl --start "${SYNO_DOCKER_SERV_NAME}"

syno_status=$(synoservicectl --status "${SYNO_DOCKER_SERV_NAME}" | grep running -o)
if [ "${syno_status}" != 'running' ] ; then
Expand Down Expand Up @@ -899,7 +946,7 @@ main() {
execute_download_compose
;;
install )
total_steps=6
total_steps=7
detect_current_versions
execute_prepare
define_target_download
Expand All @@ -909,10 +956,11 @@ main() {
execute_extract_bin
execute_install_bin
execute_update_log
execute_update_script
execute_start_syno
;;
restore )
total_steps=5
total_steps=6
detect_current_versions
execute_prepare
define_restore
Expand All @@ -921,10 +969,11 @@ main() {
execute_stop_syno
execute_restore_bin
execute_restore_log
execute_restore_script
execute_start_syno
;;
update )
total_steps=9
total_steps=10
detect_current_versions
execute_prepare
define_target_version
Expand All @@ -937,6 +986,7 @@ main() {
execute_extract_bin
execute_install_bin
execute_update_log
execute_update_script
execute_start_syno
execute_clean
;;
Expand Down

0 comments on commit b9a15fa

Please sign in to comment.