Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

modified for DSM 7.2, 7.1.1, and default to local logger #63

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
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
40 changes: 34 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@
| :warning: The repository 'Synology-Docker' is not supported by Synology and can potentially lead to malfunctioning of your NAS. Use this script at your own risk. Please keep a backup of your files. |
| --- |

| :warning: If you're using the Nvidia driver on your synology, you will need to re-start the Nvidia driver, or re-run `nvidia-ctk runtime configure` to re-add the nvidia runtime after each run of this script in order for the driver to get re-added to docker. |
| --- |

| :exclamation: Portainer Users - Portainer currently has an [issue](https://github.com/portainer/portainer/issues/10462) where it persists the first-used logging driver alongside container definitions. You may have to completely recreate (or duplicate and edit) containers created in portainer to use the `local` log driver. It would be best to do that with all of your containers BEFORE running this update. Portainer has created some challenges for users migrating from one log driver to another. You may need to spend more time re-creating containers after this update than if you were using compose.
| --- |

[Synology][synology_url] is a popular manufacturer of Network Attached Storage (NAS) devices. It provides a web-based user interface called Disk Station Manager (DSM). Synology also supports Docker on selected [models][synology_docker]. Docker is a lightweight virtualization application that gives you the ability to run containers directly on your NAS. The add-on package provided by Synology to install Docker is typically a version behind on the latest available version from Docker. *Synology-Docker* is a POSIX-compliant shell script to update both the Docker Engine and Docker Compose on your NAS to the latest version or a specified version.

<!-- TODO: add tutorial deep-link
Expand All @@ -51,7 +57,7 @@ Detailed background information is available on the author's [personal blog][blo
The project uses [Docker][docker_url], a lightweight virtualization application.

## Prerequisites
*Synology-Docker* runs on a Synology NAS with DSM 6 or DSM 7. The script has been tested with a DS918+ running DSM 6.2.4-25556 and DSM 7.0.1-42218. Other prerequisites are:
*Synology-Docker* runs on a Synology NAS with DSM 6 or DSM 7. The script has been tested with a DS918+ running DSM 6.2.4-25556, DSM 7.0.1-42218, and DSM 7.2.1-69057. Other prerequisites are:

* **SSH admin access is required** - *Synology-Docker* runs as a shell script on the terminal. You can enable SSH access in DSM under `Control Panel ➡ Terminal & SNMP ➡ Terminal`.

Expand All @@ -63,19 +69,41 @@ The project uses [Docker][docker_url], a lightweight virtualization application.
Deployment of *Synology-Docker* is a matter of cloning the GitHub repository. Login to your NAS terminal via SSH first. Assuming you are in the working folder of your choice, clone the repository files. Git automatically creates a new folder `synology-docker` and copies the files to this directory. Then change your current folder to simplify the execution of the shell script.

```console
$ git clone https://github.com/markdumay/synology-docker.git
$ cd synology-docker
git clone https://github.com/telnetdoogie/synology-docker.git
cd synology-docker
```

<!-- TODO: TEST CHMOD -->

## Preparation before upgrade
If you're using *compose* for your containers, I highly recommend that before you run the upgrade (or restore, if you're going back to the original version) you go through and stop each running container.
```console
cd /volume1/docker/{my_container}
docker-compose down
```
Because this upgrade modifies the default logger for docker, stopping (removing) and re-starting each container is required, since the logging mechanism is persisted during a compose docker build / start. You don't HAVE to do this before the upgrade, however if you don't, you'll get errors related to the logger for your containers, and will have to stop and start each container / stack after the upgrade anyway.

Stopping all the containers prior to the upgrade / restore will also make the upgrade a lot faster, since the service stop and restart normally has to do the work of stopping and starting all containers.

For a convenient way of enumerating all of the running compose projects, run the script:

```console
./syno_docker_list_containers.sh
```

...if you see a container listed with !---not_managed_by_compose---! you'll need to make sure you know how to recreate this container after the upgrade.

## Usage
*Synology-Docker* requires `sudo` rights. Use the following command to invoke *Synology-Docker* from the command line.

```console
$ sudo ./syno_docker_update.sh [OPTIONS] COMMAND
sudo ./syno_docker_update.sh [OPTIONS] COMMAND
```





### Commands
*Synology-Docker* supports the following commands.

Expand Down Expand Up @@ -113,11 +141,11 @@ Under the hood, the five different commands invoke a specific workflow or sequen
* **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`
* **I) Update log driver** - Replaces Synology's log driver with a default log driver `local` to improve compatibility while optimizing writes and limiting log file growth. 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) 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`.
* **M) Start Docker daemon** - Starts the Docker daemon by invoking `synoservicectl --start pkgctl-Docker` (or `synopkg start ContainerManager` on DSM 7).
* **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.


Expand Down
43 changes: 43 additions & 0 deletions syno_docker_list_containers.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/bin/bash

# Store container information in an array
containers_info=()
readonly NOT_COMPOSE="!---not_managed_by_compose---!"
readonly MAYBE_PORTAINER="!---maybe_managed_by_portainer---!"

# Get the list of containers and their compose locations
for c in $(docker ps -q); do
container_info=$(docker inspect "$c" --format "{{.Name}} {{if index .Config.Labels \"com.docker.compose.project.config_files\"}}{{index .Config.Labels \"com.docker.compose.project.config_files\"}}{{else}}${NOT_COMPOSE}{{end}}")
containers_info+=("$container_info")
done

# Sort the array based on the second field (compose location)
IFS=$'\n' sorted_containers_info=($(printf "%s\n" "${containers_info[@]}" | sort -u -t " " -k 2))

# Calculate the maximum length for the container names and compose locations
max_container_length=0
max_location_length=0
for info in "${sorted_containers_info[@]}"; do
container=$(echo "$info" | awk '{print $1}')
location=$(echo "$info" | awk '{print $2}')
[ ${#container} -gt $max_container_length ] && max_container_length=${#container}
[ ${#location} -gt $max_location_length ] && max_location_length=${#location}
done

# Print the header
printf "%-${max_container_length}s %s\n" "Container" "Compose_Location"
printf "%-${max_container_length}s %-${max_location_length}s\n" \
"$(printf '%*s' "${max_container_length}" '' | tr ' ' '-')" \
"$(printf '%*s' "${max_location_length}" '' | tr ' ' '-')"


# Print the sorted container information
for info in "${sorted_containers_info[@]}"; do
container=$(echo "$info" | awk '{print $1}')
location=$(echo "$info" | sed -e 's/^[^ ]* //')
if [ "$location" != "$NOT_COMPOSE" ] && [ ! -f $location ];then
location="${MAYBE_PORTAINER}"
fi
printf "%-${max_container_length}s %s\n" "$container" "$location"
done

74 changes: 44 additions & 30 deletions syno_docker_update.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,19 @@
# Comments : Use this script at your own risk. Refer to the license for the warranty disclaimer.
#======================================================================================================================

#======================================================================================================================
# Displays error message on console and terminates with non-zero error.
#======================================================================================================================
# Arguments:
# $1 - Error message to display.
# Outputs:
# Writes error message to stderr, non-zero exit code.
#======================================================================================================================
terminate() {
printf "${RED}${BOLD}%s${NC}\n" "ERROR: $1"
exit 1
}

#======================================================================================================================
# Constants
#======================================================================================================================
Expand All @@ -26,10 +39,13 @@ 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_NAME6='pkgctl-Docker'
readonly SYNO_DOCKER_SERV_NAME7='Docker'
readonly SYNO_SERVICE_TIMEOUT='5m'
readonly SYNO_DOCKER_DIR='/var/packages/Docker'
[ -d "/var/packages/ContainerManager" ] && readonly SYNO_DOCKER_DIR='/var/packages/ContainerManager' && \
readonly SYNO_DOCKER_SERV_NAME='ContainerManager'
[ -d "/var/packages/Docker" ] && readonly SYNO_DOCKER_DIR='/var/packages/Docker' && \
readonly SYNO_DOCKER_SERV_NAME='pkgctl-Docker'
if [ -z "$SYNO_DOCKER_DIR" ]; then
terminate "Docker (or ContainerManager) folder was not found."
fi
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"
Expand All @@ -38,11 +54,22 @@ 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\",
\"log-driver\" : \"local\",
\"log-opts\" : {
\"max-size\" : \"10m\",
\"max-file\" : \"3\"
},
\"registry-mirrors\" : [],
\"group\": \"administrators\"
}"
readonly SYNO_DOCKER_SCRIPT_FORWARDING='# ensure IP forwarding\n\t\tsudo iptables -P FORWARD ACCEPT\n'
readonly SYNO_SERVICE_STOP_TIMEOUT='5m'
RUNNING_CONTAINERS=$(docker ps -q 2>/dev/null | wc -l 2>/dev/null || echo 0)
if [ "$RUNNING_CONTAINERS" -gt 5 ]; then
readonly SYNO_SERVICE_START_TIMEOUT=$(echo "$RUNNING_CONTAINERS * 1.5" | bc)m
else
readonly SYNO_SERVICE_START_TIMEOUT='5m'
fi


#======================================================================================================================
Expand Down Expand Up @@ -103,19 +130,6 @@ usage() {
echo
}

#======================================================================================================================
# Displays error message on console and terminates with non-zero error.
#======================================================================================================================
# Arguments:
# $1 - Error message to display.
# Outputs:
# Writes error message to stderr, non-zero exit code.
#======================================================================================================================
terminate() {
printf "${RED}${BOLD}%s${NC}\n" "ERROR: $1"
exit 1
}

#======================================================================================================================
# Print current progress to the console and shows progress against total number of steps.
#======================================================================================================================
Expand Down Expand Up @@ -613,20 +627,20 @@ execute_stop_syno() {
if [ "${stage}" = 'false' ] ; then
case "${dsm_major_version}" in
"6")
syno_status=$(synoservicectl --status "${SYNO_DOCKER_SERV_NAME6}" | grep running -o)
syno_status=$(synoservicectl --status "${SYNO_DOCKER_SERV_NAME}" | grep running -o)
if [ "${syno_status}" = 'running' ] ; then
timeout --foreground "${SYNO_SERVICE_TIMEOUT}" synoservicectl --stop "${SYNO_DOCKER_SERV_NAME6}"
syno_status=$(synoservicectl --status "${SYNO_DOCKER_SERV_NAME6}" | grep stop -o)
timeout --foreground "${SYNO_SERVICE_STOP_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"
fi
fi
;;
"7")
syno_status=$(synopkg status "${SYNO_DOCKER_SERV_NAME7}" | grep started -o)
syno_status=$(synopkg status "${SYNO_DOCKER_SERV_NAME}" | grep started -o)
if [ "${syno_status}" = 'started' ] ; then
timeout --foreground "${SYNO_SERVICE_TIMEOUT}" synopkg stop "${SYNO_DOCKER_SERV_NAME7}"
syno_status=$(synopkg status "${SYNO_DOCKER_SERV_NAME7}" | grep stopped -o)
timeout --foreground "${SYNO_SERVICE_STOP_TIMEOUT}" synopkg stop "${SYNO_DOCKER_SERV_NAME}"
syno_status=$(synopkg status "${SYNO_DOCKER_SERV_NAME}" | grep stopped -o)
if [ "${syno_status}" != 'stopped' ] ; then
terminate "Could not stop Docker daemon"
fi
Expand Down Expand Up @@ -927,14 +941,14 @@ execute_restore_script() {
# Started Docker daemon, or a non-zero exit code if the start failed or timed out.
#======================================================================================================================
execute_start_syno() {
print_status "Starting Docker service"
print_status "Starting Docker service - May take a while to restart ${RUNNING_CONTAINERS} containers... (up to ${SYNO_SERVICE_START_TIMEOUT})"

if [ "${stage}" = 'false' ] ; then
case "${dsm_major_version}" in
"6")
timeout --foreground "${SYNO_SERVICE_TIMEOUT}" synoservicectl --start "${SYNO_DOCKER_SERV_NAME6}"
timeout --foreground "${SYNO_SERVICE_START_TIMEOUT}" synoservicectl --start "${SYNO_DOCKER_SERV_NAME}"

syno_status=$(synoservicectl --status "${SYNO_DOCKER_SERV_NAME6}" | grep running -o)
syno_status=$(synoservicectl --status "${SYNO_DOCKER_SERV_NAME}" | grep running -o)
if [ "${syno_status}" != 'running' ] ; then
if [ "${force}" != 'true' ] ; then
terminate "Could not bring Docker Engine back online"
Expand All @@ -944,9 +958,9 @@ execute_start_syno() {
fi
;;
"7")
timeout --foreground "${SYNO_SERVICE_TIMEOUT}" synopkg start "${SYNO_DOCKER_SERV_NAME7}"
timeout --foreground "${SYNO_SERVICE_START_TIMEOUT}" synopkg start "${SYNO_DOCKER_SERV_NAME}"

syno_status=$(synopkg status "${SYNO_DOCKER_SERV_NAME7}" | grep started -o)
syno_status=$(synopkg status "${SYNO_DOCKER_SERV_NAME}" | grep started -o)
if [ "${syno_status}" != 'started' ] ; then
if [ "${force}" != 'true' ] ; then
terminate "Could not bring Docker Engine back online"
Expand Down Expand Up @@ -1133,4 +1147,4 @@ main() {
echo "Done."
}

main "$@"
main "$@"