diff --git a/.travis.yml b/.travis.yml index f9cd86719b1..d6a33f6320f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -57,6 +57,7 @@ cache: - $HOME/.gradle/wrapper/ before_install: + - ./tools/travis/docker.sh - pip install --upgrade pip setuptools six - pip3 install --upgrade pip setuptools six diff --git a/ansible/environments/jenkins/group_vars/openwhisk-vm1-he-de b/ansible/environments/jenkins/group_vars/openwhisk-vm1-he-de index f742d8add3b..7ef620e2fee 100755 --- a/ansible/environments/jenkins/group_vars/openwhisk-vm1-he-de +++ b/ansible/environments/jenkins/group_vars/openwhisk-vm1-he-de @@ -36,3 +36,4 @@ runtimes_enable_concurrency: true limit_action_concurrency_max: 500 invoker1_machine: openwhisk-vm3-he-de +invoker_use_runc: false diff --git a/ansible/environments/jenkins/group_vars/openwhisk-vm2-he-de b/ansible/environments/jenkins/group_vars/openwhisk-vm2-he-de index a7fe0e01436..e2825c9db27 100755 --- a/ansible/environments/jenkins/group_vars/openwhisk-vm2-he-de +++ b/ansible/environments/jenkins/group_vars/openwhisk-vm2-he-de @@ -37,3 +37,4 @@ limit_action_concurrency_max: 500 limit_invocations_per_minute: 120 invoker1_machine: openwhisk-vm1-he-de +invoker_use_runc: false diff --git a/ansible/environments/jenkins/group_vars/openwhisk-vm3-he-de b/ansible/environments/jenkins/group_vars/openwhisk-vm3-he-de index 8ee1b80264e..cf00a470737 100755 --- a/ansible/environments/jenkins/group_vars/openwhisk-vm3-he-de +++ b/ansible/environments/jenkins/group_vars/openwhisk-vm3-he-de @@ -36,3 +36,4 @@ runtimes_enable_concurrency: true limit_action_concurrency_max: 500 invoker1_machine: openwhisk-vm2-he-de +invoker_use_runc: false diff --git a/ansible/group_vars/all b/ansible/group_vars/all index c75a87ec116..9ff838b2245 100644 --- a/ansible/group_vars/all +++ b/ansible/group_vars/all @@ -182,6 +182,7 @@ invoker: useRunc: "{{ invoker_use_runc | default(true) }}" docker: become: "{{ invoker_docker_become | default(false) }}" + runcdir: "{{ invoker_runcdir | default('/run/docker/runtime-runc/moby') }}" loglevel: "{{ invoker_loglevel | default(whisk_loglevel) | default('INFO') }}" jmxremote: jvmArgs: "{% if inventory_hostname in groups['invokers'] %} diff --git a/ansible/roles/invoker/tasks/clean.yml b/ansible/roles/invoker/tasks/clean.yml index 9df25e713b9..a755f5b48f2 100644 --- a/ansible/roles/invoker/tasks/clean.yml +++ b/ansible/roles/invoker/tasks/clean.yml @@ -21,9 +21,9 @@ - name: pause/resume at runc-level to restore docker consistency shell: | DOCKER_PAUSED=$(docker ps --filter status=paused --filter name=wsk{{ invoker_index }} -q --no-trunc) - for C in $DOCKER_PAUSED; do docker-runc pause $C; done + for C in $DOCKER_PAUSED; do docker-runc --root {{ invoker.docker.runcdir }} pause $C; done DOCKER_RUNNING=$(docker ps --filter status=running --filter name=wsk{{ invoker_index }} -q --no-trunc) - for C2 in $DOCKER_RUNNING; do docker-runc resume $C2; done + for C2 in $DOCKER_RUNNING; do docker-runc --root {{ invoker.docker.runcdir }} resume $C2; done TOTAL=$(($(echo $DOCKER_PAUSED | wc -w)+$(echo $DOCKER_RUNNING | wc -w))) echo "Handled $TOTAL remaining actions." register: runc_output diff --git a/ansible/roles/invoker/tasks/deploy.yml b/ansible/roles/invoker/tasks/deploy.yml index 5a2f298f154..ef9803107c2 100644 --- a/ansible/roles/invoker/tasks/deploy.yml +++ b/ansible/roles/invoker/tasks/deploy.yml @@ -287,10 +287,19 @@ {{ invoker.confdir }}/{{ invoker_name }}:/conf,\ {{ dockerInfo['DockerRootDir'] }}/containers/:/containers,\ {{ docker_sock | default('/var/run/docker.sock') }}:/var/run/docker.sock" - +### +# The root runc directory varies based on the version of docker and runc. +# When docker>=18.06 uses docker-runc the directory is /run/docker/runtime-runc/moby. +# While docker-runc itself uses /run/runc for a root user or /run/user//runc for a non-root user. +# Currently, the invoker is running as a root user so the below configuration works as expected. +# But when the invoker needs to run as a non-root user or the version docker needs to be changed, +# the following configuration should be properly updated as well. +# +# Alternatively, we can disable the runc with invoker.userRunc = false. +# - name: set invoker runc volume set_fact: - volumes: "{{ volumes }},/run/runc:/run/runc" + volumes: "{{ volumes }},{{ invoker.docker.runcdir }}:/run/runc" when: invoker.useRunc == true - name: define options when deploying invoker on Ubuntu diff --git a/core/controller/Dockerfile b/core/controller/Dockerfile index b540124ba33..d81e1a7cdcc 100644 --- a/core/controller/Dockerfile +++ b/core/controller/Dockerfile @@ -11,20 +11,21 @@ ENV SWAGGER_UI_DOWNLOAD_SHA256=3d7ef5ddc59e10f132fe99771498f0f1ba7a2cbfb9585f986 ################################################################################################### # It's needed for lean mode where the controller is also an invoker ################################################################################################### -ENV DOCKER_VERSION=1.12.0 \ - DOCKER_DOWNLOAD_SHA256=3dd07f65ea4a7b4c8829f311ab0213bca9ac551b5b24706f3e79a97e22097f8b +# If you change the docker version here, it has implications on invoker runc support. +# Docker server version and the invoker docker version must be the same to enable runc usage. +# If this cannot be guaranteed, set `invoker_use_runc: false` in the ansible env. +ENV DOCKER_VERSION=18.06.3-ce RUN apk add --update openssl # Uncomment to fetch latest version of docker instead: RUN wget -qO- https://get.docker.com | sh # Install docker client -RUN curl -sSL -o docker-${DOCKER_VERSION}.tgz https://get.docker.com/builds/Linux/x86_64/docker-${DOCKER_VERSION}.tgz && \ -echo "${DOCKER_DOWNLOAD_SHA256} docker-${DOCKER_VERSION}.tgz" | sha256sum -c - && \ -tar --strip-components 1 -xvzf docker-${DOCKER_VERSION}.tgz -C /usr/bin docker/docker && \ -tar --strip-components 1 -xvzf docker-${DOCKER_VERSION}.tgz -C /usr/bin docker/docker-runc && \ -rm -f docker-${DOCKER_VERSION}.tgz && \ -chmod +x /usr/bin/docker && \ -chmod +x /usr/bin/docker-runc +RUN curl -sSL -o docker-${DOCKER_VERSION}.tgz https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_VERSION}.tgz && \ + tar --strip-components 1 -xvzf docker-${DOCKER_VERSION}.tgz -C /usr/bin docker/docker && \ + tar --strip-components 1 -xvzf docker-${DOCKER_VERSION}.tgz -C /usr/bin docker/docker-runc && \ + rm -f docker-${DOCKER_VERSION}.tgz && \ + chmod +x /usr/bin/docker && \ + chmod +x /usr/bin/docker-runc ################################################################################################## # Install swagger-ui @@ -44,6 +45,8 @@ RUN chmod +x init.sh RUN adduser -D -u ${UID} -h /home/${NOT_ROOT_USER} -s /bin/bash ${NOT_ROOT_USER} # It is possible to run as non root if you dont need invoker capabilities out of the controller today +# When running it as a non-root user this has implications on the standard directory where runc stores its data. +# The non-root user should have access on the directory and corresponding permission to make changes on it. #USER ${NOT_ROOT_USER} EXPOSE 8080 diff --git a/core/invoker/Dockerfile b/core/invoker/Dockerfile index 0ec0526a874..55c64a739cf 100644 --- a/core/invoker/Dockerfile +++ b/core/invoker/Dockerfile @@ -5,25 +5,30 @@ FROM scala ENV UID=1001 \ NOT_ROOT_USER=owuser -ENV DOCKER_VERSION=1.12.0 \ - DOCKER_DOWNLOAD_SHA256=3dd07f65ea4a7b4c8829f311ab0213bca9ac551b5b24706f3e79a97e22097f8b + ENV DOCKER_VERSION=18.06.3-ce +# If you change the docker version here, it has implications on invoker runc support. +# Docker server version and the invoker docker version must be the same to enable runc usage. +# If this cannot be guaranteed, set `invoker_use_runc: false` in the ansible env. + RUN apk add --update openssl # Uncomment to fetch latest version of docker instead: RUN wget -qO- https://get.docker.com | sh # Install docker client -RUN curl -sSL -o docker-${DOCKER_VERSION}.tgz https://get.docker.com/builds/Linux/x86_64/docker-${DOCKER_VERSION}.tgz && \ -echo "${DOCKER_DOWNLOAD_SHA256} docker-${DOCKER_VERSION}.tgz" | sha256sum -c - && \ -tar --strip-components 1 -xvzf docker-${DOCKER_VERSION}.tgz -C /usr/bin docker/docker && \ -tar --strip-components 1 -xvzf docker-${DOCKER_VERSION}.tgz -C /usr/bin docker/docker-runc && \ -rm -f docker-${DOCKER_VERSION}.tgz && \ -chmod +x /usr/bin/docker && \ -chmod +x /usr/bin/docker-runc +RUN curl -sSL -o docker-${DOCKER_VERSION}.tgz https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_VERSION}.tgz && \ + tar --strip-components 1 -xvzf docker-${DOCKER_VERSION}.tgz -C /usr/bin docker/docker && \ + tar --strip-components 1 -xvzf docker-${DOCKER_VERSION}.tgz -C /usr/bin docker/docker-runc && \ + rm -f docker-${DOCKER_VERSION}.tgz && \ + chmod +x /usr/bin/docker && \ + chmod +x /usr/bin/docker-runc ADD build/distributions/invoker.tar ./ COPY init.sh / RUN chmod +x init.sh + +# When running the invoker as a non-root user this has implications on the standard directory where runc stores its data. +# The non-root user should have access on the directory and corresponding permission to make changes on it. RUN adduser -D -u ${UID} -h /home/${NOT_ROOT_USER} -s /bin/bash ${NOT_ROOT_USER} EXPOSE 8080 diff --git a/core/invoker/src/main/scala/org/apache/openwhisk/core/invoker/InvokerReactive.scala b/core/invoker/src/main/scala/org/apache/openwhisk/core/invoker/InvokerReactive.scala index 5f682d71b4e..3beae5e300d 100644 --- a/core/invoker/src/main/scala/org/apache/openwhisk/core/invoker/InvokerReactive.scala +++ b/core/invoker/src/main/scala/org/apache/openwhisk/core/invoker/InvokerReactive.scala @@ -20,7 +20,8 @@ package org.apache.openwhisk.core.invoker import java.nio.charset.StandardCharsets import java.time.Instant -import akka.actor.{ActorRefFactory, ActorSystem, Props} +import akka.Done +import akka.actor.{ActorRefFactory, ActorSystem, CoordinatedShutdown, Props} import akka.event.Logging.InfoLevel import akka.stream.ActorMaterializer import org.apache.kafka.common.errors.RecordTooLargeException @@ -96,7 +97,12 @@ class InvokerReactive( "--ulimit" -> Set("nofile=1024:1024"), "--pids-limit" -> Set("1024")) ++ logsProvider.containerParameters) containerFactory.init() - sys.addShutdownHook(containerFactory.cleanup()) + + CoordinatedShutdown(actorSystem) + .addTask(CoordinatedShutdown.PhaseBeforeActorSystemTerminate, "cleanup runtime containers") { () => + containerFactory.cleanup() + Future.successful(Done) + } /** Initialize needed databases */ private val entityStore = WhiskEntityStore.datastore() diff --git a/tools/macos/README.md b/tools/macos/README.md index 4bd3fbd7d41..043309ff14e 100644 --- a/tools/macos/README.md +++ b/tools/macos/README.md @@ -26,17 +26,19 @@ If you prefer to use Docker-machine, you can follow instructions in [docker-mach The following are required to build and deploy OpenWhisk from a Mac host: -- [Docker 1.12.0](https://docs.docker.com/docker-for-mac/) +- [Docker 18.06.3](https://docs.docker.com/docker-for-mac/install/) - [Java 8](http://www.oracle.com/technetwork/java/javase/downloads/index.html) or [Open JDK 8](https://adoptopenjdk.net/releases.html#x64_mac) - [Scala 2.11](http://scala-lang.org/download/) - [Ansible 2.5.2](http://docs.ansible.com/ansible/intro_installation.html) -**Tip** Versions of Docker and Ansible are lower than the latest released versions, the versions used in OpenWhisk are pinned to have stability during continuous integration and deployment. +**Tips:** + 1. Versions of Docker and Ansible are lower than the latest released versions, the versions used in OpenWhisk are pinned to have stability during continuous integration and deployment.
+ 2. It is required to install Docker >= 18.06.2 because of this [CVE](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-5736) [Homebrew](http://brew.sh/) is an easy way to install all of these and prepare your Mac to build and deploy OpenWhisk. The following shell command is provided for your convenience to install `brew` with [Cask](https://github.com/caskroom/homebrew-cask) and bootstraps these to complete the setup. Copy the entire section below and paste it into your terminal to run it. -``` +```bash echo ' # install homebrew /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" @@ -58,7 +60,7 @@ sudo -H pip install docker==2.2.1 ansible==2.5.2 jinja2==2.9.6 couchdb==1.1 http The above section of command installs Oracle JDK 8 as the default Java environment. If you would like to install Open JDK 8 instead of Oracle JDK 8, please run the following section: -``` +```bash # install for finding alternative versions (Open JDK 8) brew tap AdoptOpenJDK/openjdk # install Open JDK 8 @@ -67,7 +69,7 @@ brew install adoptopenjdk-openjdk8 instead of -``` +```bash # install for finding alternative versions (java8) brew tap caskroom/versions # install java 8 @@ -79,7 +81,7 @@ with the shell command described above. No matter which JDK is used, make sure you correctly configure the environment variable $JAVA_HOME. # Build -``` +```bash cd /your/path/to/openwhisk ./gradlew distDocker ``` @@ -92,7 +94,7 @@ Follow instructions in [ansible/README.md](../../ansible/README.md) Follow instructions in [Configure CLI](../../docs/cli.md) ### Use the wsk CLI -``` +```bash bin/wsk action invoke /whisk.system/utils/echo -p message hello --result { "message": "hello" diff --git a/tools/macos/docker-machine/README.md b/tools/macos/docker-machine/README.md index 8cc8e161f75..ed7f63fe143 100644 --- a/tools/macos/docker-machine/README.md +++ b/tools/macos/docker-machine/README.md @@ -27,17 +27,18 @@ You will make provision of a virtual machine with Docker-machine and communicate The following are required to build and deploy OpenWhisk from a Mac host: - [Oracle VM VirtualBox](https://www.virtualbox.org/wiki/Downloads) -- [Docker 1.12.0](https://docs.docker.com/engine/installation/mac/) (including `docker-machine`) +- [Docker 18.06.3](https://docs.docker.com/machine/install-machine/) (including `docker-machine`) - [Java 8](http://www.oracle.com/technetwork/java/javase/downloads/index.html) - [Scala 2.11](http://scala-lang.org/download/) - [Ansible 2.5.2](http://docs.ansible.com/ansible/intro_installation.html) -**Tip** Versions of Docker and Ansible are lower than the latest released versions, the versions used in OpenWhisk are pinned to have stability during continues integration and deployment. - +**Tips:** +1. Versions of Docker and Ansible are lower than the latest released versions, the versions used in OpenWhisk are pinned to have stability during continues integration and deployment. +2. It is required to install Docker >= 18.06.2 because of this [CVE](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-5736) [Homebrew](http://brew.sh/) is an easy way to install all of these and prepare your Mac to build and deploy OpenWhisk. The following shell command is provided for your convenience to install `brew` with [Cask](https://github.com/caskroom/homebrew-cask) and bootstraps these to complete the setup. Copy the entire section below and paste it into your terminal to run it. -``` +```bash echo ' # install homebrew /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" @@ -65,7 +66,7 @@ sudo -H pip install docker==2.2.1 ansible==2.5.2 jinja2==2.9.6 couchdb==1.1 http It is recommended that you create a virtual machine `whisk` with at least 4GB of RAM. -``` +```bash docker-machine create -d virtualbox \ --virtualbox-memory 4096 \ --virtualbox-boot2docker-url=https://github.com/boot2docker/boot2docker/releases/download/v1.12.0/boot2docker.iso \ @@ -79,13 +80,13 @@ The following [script](./tweak-dockermachine.sh) will disable TLS, add port forw within the VM and routes `172.17.x.x` from the Mac host to the Docker virtual machine. Enter your sudo Mac password when prompted. -``` +```bash cd /your/path/to/openwhisk ./tools/macos/docker-machine/tweak-dockermachine.sh ``` The final output of the script should resemble the following two lines. -``` +```bash Run the following: export DOCKER_HOST="tcp://192.168.99.100:4243" # your Docker virtual machine IP may vary ``` @@ -96,19 +97,19 @@ from OpenWhisk. Ignore errors messages from `docker-machine ls` for the `whisk` virtual machine, this is due to the configuration of the port `4243` vs. `2376` -``` +```bash NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS whisk - virtualbox Running tcp://192.168.99.100:2376 Unknown Unable to query docker version: Cannot connect to the docker engine endpoint ``` To verify that docker is configure properly with `docker-machine` run `docker ps`, you should not see any errors. Here is an example output: -``` +```bash CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ``` You may find it convenient to set these environment variables in your bash profile (e.g., `~/.bash_profile` or `~/.profile`). -``` +```bash export OPENWHISK_HOME=/your/path/to/openwhisk export DOCKER_HOST=tcp://$(docker-machine ip whisk):4243 ``` @@ -118,13 +119,13 @@ However one of the tweaks is applied on the Mac host and must be applied again if you reboot your Mac. Without it, some tests which require direct communication with Docker containers will fail. To run just the Mac host tweaks, run the following [script](./tweak-dockerhost.sh). Enter your sudo Mac password when prompted. -``` +```bash cd /your/path/to/openwhisk ./tools/macos/docker-machine/tweak-dockerhost.sh ``` # Build -``` +```bash cd /your/path/to/openwhisk ./gradlew distDocker ``` @@ -132,7 +133,7 @@ cd /your/path/to/openwhisk # Deploy -``` +```bash brew install python pip install ansible==2.5.0 pip install jinja2==2.9.6 @@ -148,14 +149,14 @@ After this there should be a `hosts` file in the `ansible/environments/docker-ma To verify the hosts file you can do a quick ping to the docker machine: -``` +```bash cd ansible ansible all -i environments/docker-machine -m ping ``` Should result in something like: -``` +```bash ansible | SUCCESS => { "changed": false, "ping": "pong" @@ -172,7 +173,7 @@ Follow remaining instructions from [Using Ansible](../../../ansible/README.md#us Follow instructions in [Configure CLI](../../../docs/cli.md) ### Use the wsk CLI -``` +```bash bin/wsk action invoke /whisk.system/utils/echo -p message hello --result { "message": "hello" diff --git a/tools/travis/docker.sh b/tools/travis/docker.sh new file mode 100755 index 00000000000..db7bc9d09d1 --- /dev/null +++ b/tools/travis/docker.sh @@ -0,0 +1,44 @@ +#!/bin/bash +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +sudo gpasswd -a travis docker +sudo -E bash -c 'echo '\''DOCKER_OPTS="-H tcp://0.0.0.0:4243 -H unix:///var/run/docker.sock --storage-driver=overlay --userns-remap=default"'\'' > /etc/default/docker' + +# Docker +sudo apt-get clean +sudo apt-get update + +# Need to update dpkg due to known issue: https://bugs.launchpad.net/ubuntu/+source/dpkg/+bug/1730627 +sudo apt-get install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common dpkg +curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - +sudo apt-key fingerprint 0EBFCD88 + +# This is required because libseccomp2 (>= 2.3.0) is not provided in trusty by default +sudo add-apt-repository -y ppa:ubuntu-sdk-team/ppa + +sudo add-apt-repository \ + "deb [arch=$(uname -m | sed -e 's/x86_64/amd64/g')] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" + +sudo apt-get update +sudo apt-get -o Dpkg::Options::="--force-confold" --force-yes -y install docker-ce=18.06.3~ce~3-0~ubuntu containerd.io +sudo service docker restart +echo "Docker Version:" +docker version +echo "Docker Info:" +docker info + diff --git a/tools/travis/setup.sh b/tools/travis/setup.sh index f712897f253..35705e1a83a 100755 --- a/tools/travis/setup.sh +++ b/tools/travis/setup.sh @@ -30,18 +30,6 @@ function retry() { fi } -sudo gpasswd -a travis docker -sudo -E bash -c 'echo '\''DOCKER_OPTS="-H tcp://0.0.0.0:4243 -H unix:///var/run/docker.sock --storage-driver=overlay --userns-remap=default"'\'' > /etc/default/docker' - -# Docker -sudo apt-get -y update -qq -sudo apt-get -o Dpkg::Options::="--force-confold" --force-yes -y install docker-engine=1.12.0-0~trusty -sudo service docker restart -echo "Docker Version:" -docker version -echo "Docker Info:" -docker info - # Python pip install --user couchdb diff --git a/tools/ubuntu-setup/docker.sh b/tools/ubuntu-setup/docker.sh index caa74f64499..6a01fae0e23 100755 --- a/tools/ubuntu-setup/docker.sh +++ b/tools/ubuntu-setup/docker.sh @@ -19,24 +19,27 @@ set -e set -x -sudo apt-get -y install apt-transport-https ca-certificates -sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9 -sudo sh -c "echo deb https://apt.dockerproject.org/repo ubuntu-trusty main > /etc/apt/sources.list.d/docker.list" -sudo apt-get -y update +sudo sudo apt-get install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common +curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - +sudo apt-key fingerprint 0EBFCD88 + +sudo add-apt-repository \ + "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" -sudo apt-get purge lxc-docker -sudo apt-cache policy docker-engine +sudo add-apt-repository \ + "deb [arch=$(uname -m | sed -e 's/x86_64/amd64/g')] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" +sudo apt-get -y update # AUFS # Use '-virtual' package to support docker tests of the script and still run under Vagrant sudo apt-get --no-install-recommends -y install linux-image-extra-virtual # DOCKER -sudo apt-get install -y --force-yes docker-engine=1.12.0-0~trusty -sudo apt-mark hold docker-engine +sudo apt-get install -y docker-ce=18.06.3~ce~3-0~ubuntu containerd.io +sudo apt-mark hold docker-ce # enable (security - use 127.0.0.1) -sudo -E bash -c 'echo '\''DOCKER_OPTS="-H tcp://0.0.0.0:4243 -H unix:///var/run/docker.sock --storage-driver=aufs"'\'' >> /etc/default/docker' +sudo -E bash -c 'echo '\''DOCKER_OPTS="-H unix:///var/run/docker.sock --storage-driver=aufs"'\'' >> /etc/default/docker' sudo gpasswd -a "$(whoami)" docker