Installing Lando and Docker for Drupal 8 on Ubuntu

Lando and Docker

Lando is a Docker based development tool, which is much faster than Vagrant-based tools, since processes are run in containers directly on the host machine.

Install Docker

Follow the instructions on these pages;
https://docs.docker.com/install/linux/docker-ce/ubuntu/#install-using-the-repository
https://docs.docker.com/install/linux/linux-postinstall/

Fix missing ~/.docker/config.json file, from https://www.reddit.com/r/docker/comments/74cok4/missing_configjson/
# "$HOME/.docker/config.json -- If there is no such file (and/or folder) you can create it. For example"

# create folder
mkdir $HOME/.docker

# create config with empty object
echo "{}" > $HOME/.docker/config.json

Manage Docker as a non-root user
# https://docs.docker.com/install/linux/linux-postinstall/#manage-docker-as-a-non-root-user

sudo chown "$USER":"$USER" /home/"$USER"/.docker -R
sudo chmod g+rwx "$HOME/.docker" -R

Install PHP
Ubuntu 16.04:

sudo apt-get install php7.0 php7.0-cli php7.0-common php7.0-curl php7.0-dom php7.0-gd php7.0-mbstring php7.0-mysql php7.0-sqlite3 php7.0-xml

Upgrading to PHP 7.2 on Ubuntu 16.04 (Running sudo apt-get install php7.1 will also install apache):

sudo add-apt-repository ppa:ondrej/php
sudo apt-get update
sudo apt-get remove php7.0
sudo apt-get install php7.2-cli php7.2-common php7.2-curl php7.2-gd php7.2-mbstring php7.2-mysql php7.2-odbc php7.2-sqlite3 php7.2-xml

Ubuntu 18.04:

sudo apt-get install php7.2-cli php7.2-common php7.2-curl php7.2-gd php7.2-mbstring php7.2-mysql php7.2-odbc php7.2-sqlite3 php7.2-xml

Install Lando

Follow the instructions on these pages;
https://github.com/lando/lando
https://docs.devwithlando.io/installation/linux.html

# download Latest release
wget https://github.com/lando/lando/releases/download/v3.0.0-beta.47/lando-v3.0.0-beta.47.deb

# install 
sudo dpkg -i lando-v3.0.0-beta.47.deb

# remove install file
rm lando-v3.0.0-beta.47.deb

Install Composer
From https://getcomposer.org/download/

# check if /home/your_username/.local/bin is part of the registered PATH:

echo $PATH

# if not, add this line to ~/.bashrc

export PATH="~/.local/bin/:$PATH"

# make it take effect

source ~/.bashrc
# install Composer
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('SHA384', 'composer-setup.php') === '93b54496392c062774670ac18b134c3b3a95e5a5e5c8f1a9f115f203b75bf9a129d5daa8ba6a13e2cc8a1da0806388a8') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
php composer-setup.php
php -r "unlink('composer-setup.php');"

# finish installation, and commands to check and update
mkdir ~/.local/bin/ # create folder if it doesn't exist
mv composer.phar ~/.local/bin/composer
whereis composer
composer
composer selfupdate

Drupal 8 in Lando Docker

# create and enter your dev-directory, for example in ~/dev folder
# NOTE: don't call it .lando! This is where Lando configuration is written
mkdir ~/dev
cd ~/dev

# create a Drupal project. Assumes that you have Composer installed.
composer create-project drupal-composer/drupal-project:8.x-dev drupaltest --stability dev --no-interaction --no-dev

# cd into the created directory.
cd drupaltest

# launch the interactive session.
lando init

# or just specify the Drupal 8 recipe.
lando init --recipe drupal8 --webroot web --name drupaltest

# show info
lando info

# start lando
lando start

# install Drupal with Drush
lando drush site-install --db-url=mysql://drupal8:drupal8@database/drupal8 --account-pass=content -y

# log into your new site
lando drush uli -l http://drupaltest.lndo.site

# download Admin Toolbar module
composer require 'drupal/admin_toolbar'

# enable Admin Toolbar module
lando drush en admin_toolbar admin_toolbar_tools -y

# clear cache
lando drush cache-rebuild

# destroy the Lando app and delete the folder
lando destroy
cd ..
chmod -R 775 drupaltest && rm drupaltest -rf;

# add these aliases to your ~/.bashrc file to shorten "lando drush" commands
# activate with source ~/.bashrc
alias drush='lando drush'
alias dst='lando drush st'
alias duli='lando drush uli'
alias dcr='lando drush cr'
alias dexp='lando drush config-export'
alias dimp='lando drush config-import --preview=diff'

Sources
https://docs.docker.com/install/linux/docker-ce/ubuntu/
https://colorfield.be/blog/drupal-and-docker-the-easy-way-with-lando

Working offline with Lando
By default, you can't start Lando without internet access, since it uses an online service to look up a DNS entry: "Lando accomplishes this with an actual ON THE INTERNET wildcard DNS entry that points all lndo.site subdomains to localhost/127.0.0.1. This means that if you lose your internet connection, you will not be able to visit your app at these addresses."

The solution is Working Offline or Using Custom Domains by adding your custom domain in your /etc/hosts file, like this:

# Get my `lndo.site` domain to work offline
127.0.0.1 myapp.lndo.site

# If you have defined an extra domain
127.0.0.1 admin.myapp.lndo.site

IMPORTANT: You will need to do a lando poweroff to apply these changes.

Extra Docker tips
Clean up and delete containers, for more info, see https://colorfield.be/blog/cleaning-lando-containers

docker ps --all
docker kill $(docker ps -q)
docker rm $(docker ps -a -q)
docker rmi $(docker images -q)

# disable Docker from starting on boot
# check Docker status
sudo systemctl list-unit-files | grep -i docker

# result
docker.service                             enabled 
docker.socket                              enabled 

# disable Docker from starting on boot
sudo systemctl disable docker.service
sudo systemctl disable docker.socket

# remove unused Docker networks, if they conflict with VPN connection
docker network prune

Fix VPN Docker IP conflict
Dockers default IP ranges at 172.17.* 172.18.* 172.19.* might conflict with your VPN, if it uses the same ranges.

Adding this to `/etc/docker/daemon.json` and restarting Docker updates both `docker0` and the bridges (like `br-eb18f822dc96`):

{
        "default-address-pools":
        [
                {"base":"172.90.0.0/16","size":24}
        ]
}

Result

$ ip addr | grep 172
    inet 172.90.0.1/24 brd 172.90.0.255 scope global docker0
    inet 172.90.1.1/24 brd 172.90.1.255 scope global br-c71a376aa530
    inet 172.90.2.1/24 brd 172.90.2.255 scope global br-9a2279ba5e4f
    inet 172.90.3.1/24 brd 172.90.3.255 scope global br-ff55447fdd53

Some suggest this in `daemon.json`, but it only updates the IP for `docker0`, but not the bridges:

{
  "bip" : "172.90.0.1/24"
}

stop and start Docker again

sudo systemctl stop docker
sudo systemctl start docker