# data[].attributes.body
Attendance Matt, Mark M, Tyler, Jevon

Wrapping up, ensuring all code checked in, and completing RDP Status Reports.

# data[].attributes.body
Kick off: Nathan, Brady, Ruben, and Ali in attendance.

The team is starting by getting their Pi's imaged with VNC Viewer for remote connectivity. The team is also completing some Docker tutorials.

We need to cross train Brady on the IT tasks for the 4 node Pi Cluster and also validate the cluster is still working. Tyler will help with this cross training.

# data[].attributes.body
Attendance Brendan, Mark M, Matt, Jevon, and Tyler

Project wrap up and preparation for Technical Advisory Board demo.
Presentation ready.
Demo ready.
No outstanding issues.

# data[].attributes.body
1. Plug a USB keyboard and Mouse into the Pi.
2. Plug the HDMI cable with a monitor into the Pi.
3. Install NOOBS on the SD Card per the Padlet Card below.
4. Insert the SD Card into the Pi.
5. Power up the Pi.
6. Install Raspbian OS per the install instructions when NOOBS starts up.
7. Restart the Pi to boot the Raspbian OS.
8. Go to vnc.com and setup an account. Download and install the VNC Viewer application.
9. Enable VNC on the Pi and sign into your VNC account. See Padlet Card below.

You should now be able to access your PI via VNC Viewer from any Wifi network and without a keyboard, mouse, or monitor attached to your Pi.

# data[].attributes.body
Attendance Jevon, Matt, Mark M, Chuong, Brendan

Project wrap up and preparation for Technical Advisory Board demo:
1) Presentation Deck
2) Get Tomcat to work
3) Display Visualizer?
3) Clean up Portal App UI (logo, etc)
4) GIT checkin all Portal App code
5) GIT checkin all Java API code

# data[].attributes.body
Attendance Jevon, Matt, Brendan, Mark M, Tyler, Chuong, and William.

Preparing Portal App for Symposium and doing first integration with Nginx and Tomcat.

# data[].attributes.body
Attendance Brendan, Mark M, Tyler, Chuong, and Matt.

Cluster is built out to 5 with an extra spare that is now available. Tyler is looking deeper in the network design to determine how to connect to Workers.

For the Portal App still being worked on. Brendan is still working volume extensions for the Java API.

Goal is to get Portal App and Cluster integrated with Java API this week.

Mark has manually created with docker CLI a MySQL and Tomcat 8.5 running CST-341 ICA.

# data[].attributes.body
Attendance Brendan,  Mark M, Tyler, Tayler, Matt, and Jevon.

Cluster is built out to 5. Visualizer now working. Enabled and tested the Remote API on the Master. Trying to also resolve how to use subdomains to access he node in the cluster.

For the Portal App working on the front end pages, Mark M working Settings display page, Taylor working on Product Catalog page, Chuong getting started on some of the backend database work. Matt working on lots of UI refinements and enhancements.

Brenda working with Mark M and William on Storage Strategy and how this will need to be supported in the Java API.

# data[].attributes.attachment_link.description
Recently, the Raspberry Pi Foundation have released a really easy way to set up your SD Card. It's called the New Out Of Box Software (or NOOBS for short) and provides a really easy way to install Raspberry Pi distributions.

# data[].attributes.body
Attendance Brendan,  Mark M, Tyler, Matt, and Jevon.

Continued networking the cluster. Visualizer does not work. Trying to also resolve how to use subdomains to access he node in the cluster. Need to enable the Remote API on the Master.

For the Portal App working on the front end pages, Mark M working Settings display page, Taylor working on Product Catalog page, Chuong getting started on some of the backend database work.

Brendan got the Java API working on his PI. Brendan will be meeting with Mark M and William on Storage Strategy and how this will need to be supported in the Java API.

# data[].attributes.body
Attendance Brendan, William, Mark M, Chuong.

Continued networking the cluster. Visualizer does not work.

For the Portal App working on the front end pages, Mark M working Settings display page, Taylor working on Product Catalog page, Chuong getting started on some of the backend database work.

Brendan is working on Java API which still has a pending with issue getting to restart docker daemon without an error. Going to reinstall Docker to see if the issue goes away. This may be a docker version issue as installing docker 18.06.01 resolved the issues. More testing to be done.

William working on Storage Strategy. Remote connectivity testings in progress so MySQL on Docker can be tested with MySQL Workbench.

# data[].attributes.body
Matt, Taylor, Brendan, Mark M, Tyler,   Chuong, Taylor, and Jevon. Network cluster of 4 now working in a Swarm. The SD Card install script is now also complete but needs a few refinements to ensure Visualizer is installed on the Master. The Portal Application has login, registration, and skeleton Product Catalog. No updates on zRam performance testing. The Java API is not connecting from Windows 10 but has been validated on vmWare Ubuntu images.

# data[].attributes.body
William, Brendan, Chuong, Matt, and Ruben in attendance. Network design and implementation still in progress. Mark M was ill so no updated on Portal App. zRam working but still needs to be benchmarked. Still trying to get API hooked up to Pi or Linux VM.

# data[].attributes.body
William, Brendan, Mark M, Chuong, and Tayler in attendance. Network design and implementation still in progress. Hopefully will get completed by next week. Portal App design wrapping up. Hopefully will get done by next week. Reviewed draft design today. zRam working but is be benchmarked. Still trying to get API hooked up to Pi or Linux VM.

# data[].attributes.body
Jevon, Chuong, Matt, Ruben, Athena, Will, Brendan, Ruben, Mark M in attendance. High level design for Portal App started. Network design started. Client API cloned and being tested. zRam being tested and evaluated as an option to expand RAM to 2G.

# data[].attributes.body
https://www.realvnc.com/en/connect/docs/raspberry-pi.html#establishing-a-cloud-connection

# data[].attributes.body
Brady, Reuben, and Nathan in attendance.

Brady will the 20 node cluster configured and operational this week. Reuben is troubleshooting the detached issue for PHP and NodeJS containers. Nathan is starting to look at building the Portal app and coming up to speed on docker storage.

# data[].attributes.body
Jevon, Chuong, Matt, Ruben, Taylor, Athena, Will, Brendan, Mark M in attendance. The team reviews draft system, network, and storage designs. Tasks for the Portal, Java API, Network Design, and Storage Design were assigned out to team members.

# data[].attributes.body
Mark, Athena and Tyler in attendance. The entire team has the assignment over the break to complete the Docker Swarm tutorials and setup a Swarm using Ubuntu Server, VirtualBox or Vmware Fusion, locally on their laptop.

# data[].attributes.body
Chuong, Brendan, Aaron, and Athena in attendance. The team is finishing up some training on building Docker images and running Docker images. The team is still finishing up the tutorials on Docker Swarm. NodeJS testing was finished.

# data[].attributes.body
Aaron, Mark M, Brendan, Will, and Tyler in attendance. Discussed testing strategy and resources for Docker Swarm. Team started validating some of the custom images. Team started on Docker Swarm tutorials and a local Docker Swarm POC using Vmware, VirtualBox, or docker-machine.

# data[].attributes.body
The PHP Docker Images is running, the basic Tomcat Docker Image is running, and number of other Docker Images are in progress. See the RDP Task List in Shared Documents. No updates from Tyler. Waiting for Trevor to join the team

# data[].attributes.body
Divided up Products for Docker (JBoss, Tomcat, Apache PHP, Python, Python AI, and NodeJS. Goal is to get Docker Containers and Images working for all Products to start building our a default Docker Library. See the attached for the current Task List.

# data[].attributes.attachment_link.readable_text
JBoss: Athena
Tomcat: William
Apache PHP: Mark M.
NodeJS: Brendan
Python: Mark M
Python with AI: Mark M
MySQL: Tyler
PostGreSQL: Tyler

Bash Setup Utility Script: Tyler
Network Design: Tyler

# data[].attributes.body
A number of team members already have the OS installed on their Pi. We spent an hour this week during our meeting to get the OS installed on the 2 remaining Pi's. We then walked thru how to get VNC Viewer running. A could of team members have Docker running by simply using the documentation on the Raspberry Pi home page. Basically you have to run the following command:
curl -sSL https://get.docker.com | sh.

See https://www.raspberrypi.org/blog/docker-comes-to-raspberry-pi/.

# data[].attributes.body
Received 10 Pi's, power supplies, SD, and cases. These were distributed to each team member to start imaging the SD card and OS. We did not get the SENSE HAT's.

See https://elinux.org/RPi_Easy_SD_Card_Setup for how install NOOBS.

# data[].attributes.body
The team is waiting for the equipment so are still reading tutorials on Docker Kubernetes. A couple of students who own Pi’s will start exploring Docker on the Pi.

# data[].attributes.body
The team is starting by completing some Docker tutorials. We are still waiting for the arrival of our equipment to start our project.

# data[].attributes.attachment_link.readable_text
If you like tinkering with Docker and have a Raspberry PI available, you're in luck! You can now install Docker on your RPI without messing with complicated stuff, fire up a terminal and follow this tutorial.

Prerequisites

I take absolutely NO responsibility of what you do with your machine; use this tutorial as a guide and remember you can possibly cause data loss if you touch things carelessly.

In order to follow this tutorial you will need:

A Raspberry PI with Raspbian Wheezy, Jessie, Stretch or superior.

Administrator privileges

About 10 minutes if you have a fast connection.

Setting up the required software

In this step we're going to install the required software in order to set up the Docker repository correctly and safely:

Now it is time to acquire the GPG key:
If you want to check the fingerprint here it is for reference (if you don't trust me, and that's perfectly fine, verify on the official website): 9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88.

Add the repository

In this step we're going to add the repository:

Install Docker CE

And finally:

And voilà! You now have installed Docker on your Raspberry PI! You can continue your reading about Docker here:

The following two tabs change content below.

# data[].attributes.attachment_link.title
How to Docker on Raspberry PI (Raspbian) - Marksei

# data[].attributes.attachment_link.description
If you like tinkering with Docker and have a Raspberry PI available, you're in luck! You can now install Docker on your RPI without messing with complicated stuff, fire up a terminal and follow this tutorial.

# data[].attributes.body
Nathan, Brady, and Ruben in attendance.

All team members that attended now have their Pi’s setup with VNC. The team will continue with Docker and Docker Swarm tutorials on their Pi. The leads for the Portal App, Java API, and Cluster were assigned out. Brady and Tyler are still cross training.

# data[].attributes.attachment_link.description
The Play with Docker classroom brings you labs and tutorials that help you get hands-on experience using Docker. In this classroom you will find a mix of labs and tutorials that will help Docker users, including SysAdmins, IT Pros, and Developers.

# data[].attributes.attachment_link.description
The Play with Kubernetes classroom is a new site provided by Docker that helps you get hands-on experience using Kubernetes. We provide a workshop that will allow you, in the browser, to follow a Kubernetes tutorial without having to install a single thing.

# data[].attributes.attachment_link.readable_text
Docker is a very useful tool for running containerized versions of popular applications (such as databases) or setting up some IoT service on an internet-connected device.

But installing Docker can sometimes be a hassle if it needs to be done a number of times across different computers. The silver lining, however, is that there is a handy trick hidden away in the Docker docs detailing how to install Docker with just two lines in the terminal.

Yes, you heard right! With just two lines you can load and install Docker.

Installing Docker can be handled by a bash script which will automate the entire installation. Docker provides such a script at get.docker.com . The first command will be consuming this URL, looking for a file called get-docker.sh . Once gotten, we just run the script. The two commands can be chained together to form a statement like:

curl -fsSL get.docker.com -o get-docker.sh && sh get-docker.sh

Now you have Docker installed, and the installation only took two lines.

As you just saw, the two commands above are chained together using the '&&' operator. This means that the commands will run one after the other, but can be typed on the same line.

One small issue, though, is that you might experience difficulty running Docker commands without sudo. This can be fixed, but it'll take a few more lines.

How to set up Docker to run without using sudo all the time

I discovered this solution on AskUbuntu after encountering the problem. Let's go through it now.

There are 3 steps:

Add the Docker group if it doesn't already exist:

sudo groupadd docker

2. Add the connected user "$USER" to the docker group. Change the user name to match your preferred user if you do not want to use your current user:

sudo gpasswd -a $USER docker

3. From here you have two options: either logout and then log back in, or run newgrp docker for the changes to take effect.

You should now be able to run Docker without sudo. To test, try this:

docker run hello-world

If it worked, you should see a lovely message from Docker:

Again, all credit for this solution goes to this great AskUbuntu answer I found. Without typing sudo all the time, commands will be much easier to work with.

But wait, there's more!

What if you want docker-compose also? You could try and install the docker-compose source similarly to how we installed Docker. One interesting approach I found on the Google Cloud Engines docs is that you can actually run docker-compose as a container itself!

Doing so means you have a disposable installation of docker-compose which will be used to compose your services. At any point, you can throw it away and repeat the steps for a fresh docker-compose.

First step will be running docker-compose as a container and giving it access to volumes.

docker run \
 -v /var/run/docker.sock:/var/run/docker.sock \
 -v "$PWD:/rootfs/$PWD" \
 -w="/rootfs/$PWD" \
 docker/compose:1.13.0 up

Next, make an alias to docker compose:

echo alias docker-compose="'"'docker run \
 -v /var/run/docker.sock:/var/run/docker.sock \
 -v "$PWD:/rootfs/$PWD" \
 -w="/rootfs/$PWD" \
 docker/compose:1.13.0'"'" >> ~/.bashrc

Then reload bash:

source ~/.bashrc

Now you have full access to docker-compose. The alias defined above means that rather than having to type out docker commands when you want to use the compose container, you can just use 'docker-compose' as you normally would.

Important Notice about Docker on RPi

Raspberry Pi's use ARM archetecture, and as a result wont be compatible with all containers out of the box. Images will need to be built from an ARM base image.

You can see this in action by running a containerized Redis instance on a Raspberry Pi (which is quite relevant to an upcoming series I'm writing). Doing so will require working with a base image. Provided we use an ARM-compatible image, no problems should arise. The issue is finding a well-maintained one.

If you enjoyed this article, give it a clap.

I have other posts on my page related to Microservices, Ionic, and more.

# data[].attributes.attachment_link.title
The easy way to set up Docker on a Raspberry Pi - freeCodeCamp.org

# data[].attributes.attachment_link.description
Docker is a very useful tool for running containerized versions of popular applications (such as databases) or setting up some IoT service on an internet-connected device. But installing Docker can sometimes be a hassle if it needs to be done a number of times across different computers.

# data[].attributes.headline
How to install Docker on your Raspberry Pi

# data[].attributes.subject
How to install Docker on your Raspberry Pi

# data[].attributes.attachment_link.readable_text
Docker is a tool that allows you to deploy applications inside of software containers. This can be useful for the Raspberry Pi because it allows users to run applications with very little overhead, as long as the application is packaged inside of a Docker image. You simply install Docker and run the container. This guide will walk you through the process of installing Docker on Raspbian Jessie.
Update: Although this guide is still relevant, some people are experiencing issues with the add-apt-repository command. I've added a note in the appropriate step below for those that wish to follow the guide I've laid out, but I believe the best way moving forward is to use a much simpler method and install directly from get.docker.com. See the example below.
curl -sSL https://get.docker.com | sh

1
Since Raspbian is Debian based, we will use apt to install Docker. But first, we need to update.

sudo apt-get update

2
sudo apt-get install apt-transport-https \ ca-certificates \ software-properties-common

3
curl -fsSL https://yum.dockerproject.org/gpg | sudo apt-key add -

Verify the correct key id:

apt-key fingerprint 58118E89F3A912897C070ADBF76221572C52609D

Set up the stable repository:

sudo add-apt-repository \ "deb https://apt.dockerproject.org/repo/ \ raspbian-$(lsb_release -cs) \ main"
Note: If you're experiencing issues with the add-apt-repository command, you can add the line directly to the sources.list file. See below:
sudo vim /etc/apt/sources.list

Append the following:

https://apt.dockerproject.org/repo/ raspbian-jessie main

4
First, update apt again.

sudo apt-get update

Now install Docker Engine.

sudo apt-get -y install docker-engine

5
To test docker we'll run the hello-world image.

docker run hello-world

If Docker is installed properly, you'll see a "Hello from Docker!" message.

Docker images are made up of layers, and many times you'll want to see details on each layer of an image. This guide will show you how to show all layers of a Docker image.

Docker secrets is a secrets management tool designed for use with Docker Swarm. And of course, Docker Swarm refers to the cluster management and orchestration features built into the Docker Engine.

A cluster is a group of computers performing the same task, operating as a single system. Although Raspberry Pi's are pretty incredible devices, a single Pi can only do so much.

Docker is an open-source that aims to automate the deployment of applications inside containers. Ea...

The Raspberry Pi is a small, inexpensive computer developed by the Raspberry Pi Foundation in the U...

# data[].attributes.attachment_link.title
How to install Docker on your Raspberry Pi

# data[].attributes.attachment_link.description
Docker is a tool that allows you to deploy applications inside of software containers. This can be useful for the Raspberry Pi because it allows users to run applications with very little overhead, as long as the application is packaged inside of a Docker image. You simply install Docker and run the container.

# data[].attributes.attachment_link.readable_text
If you're not already familiar with Docker, it's a method of packaging software to include not only your code, but also other components such as a full file system, system tools, services, and libraries. You can then run the software on multiple machines without a lot of setup. Docker calls these packages containers.

Think of it like a shipping container and you've got some idea of how it works. Shipping containers are a standard size so that they can be moved around at ports, and shipped via sea or land. They can also contain almost anything. Docker containers can hold your software's code and its dependencies, so that it can easily run on many different machines. Developers often use them to create a web application server that runs on their own machine for development, and is then pushed to the cloud for the public to use.

While we've noticed people using Docker on Raspberry Pi for a while now, the latest release officially includes Raspbian Jessie installation support. You can now install the Docker client on your Raspberry Pi with just one terminal command:
curl -sSL https://get.docker.com | sh
From there, you can create your own container or download pre-made starter containers for your projects. The documentation is thorough and easy to follow. You can also follow this Pi-focused guide by Docker captain Alex Ellis.

Docker Swarm

One way you can use Raspberry Pi and Docker together is for Swarm. Used together, they can create a computer cluster. With Swarm containers on a bunch of networked Raspberry Pis, you can build a powerful machine and explore how a Docker Swarm works. Alex shows you how in this video:

Get all the details @ http://blog.alexellis.io/live-deep-dive-pi-swarm/

You can follow along with Alex's written tutorial as well. He has even taken it further by using Pi Zero's USB gadget capabilities to create a tiny Docker Swarm:

Look ma, no Ethernet! 8 core @Docker 1.12 swarm boom USB OTG @Raspberry_Pi @pimoroni

The Raspberry Pi already makes many computing tasks easier; why not add deploying remote applications to that list with Docker?

# data[].attributes.attachment_link.title
Docker comes to Raspberry Pi - Raspberry Pi

# data[].attributes.attachment_link.description
If you're not already familiar with Docker, it's a method of packaging software to include not only your code, but also other components such as a full file system, system tools, services, and libraries. You can then run the software on multiple machines without a lot of setup.

# data[].attributes.attachment_link.readable_text
I have put this guide together to help you get started with Docker 1.12 (or newer) on your Raspberry Pi. For simplicity we will use the default operating system for the Pi - called Raspbian. This guide currently works with most models of Raspberry Pi and I'd recommending using the Model B 2/3 or Zero.
Raspberry Pi Zero Cluster
Don't know what Docker is yet or what you could use it for? Check out Understanding Docker from the offical docs.

Already using Docker on your Pi?

Head straight over to my Live Swarm Deep Dive video where we connect multiple Raspberry Pis to together to create a Docker Swarm.

Preparing the SD card

Download the latest Raspbian Jessie Lite image from https://www.raspberrypi.org/downloads/raspbian/.

The Raspbian Jessie Lite image is the same as the regular image but only contains the bare minimum amount of packages.

I used to give instructions for using dd on Mac and Linux with a third option for Windows. Now I recommend Etcher.io which will flash your SD card in the same way whichever of those Operating Systems you use on your PC/laptop.

Download Etcher here:

Now follow the instructions in Etcher to flash your SD card. There is one more thing we have to do before ejecting the SD card.

Enable SSH on the SD Card

To help prevent Raspberry Pis around the globe from being hacked the RPi foundation have now disabled SSH on the default image. Just create a text file in /boot/ called ssh - it can be blank or you can type anything you want inside it.

Make sure it has no extension such as ssh.txt - it must just be ssh.

Now insert the SD card, networking and power etc.

Install Docker

Once you boot up the Raspberry Pi you will be able to locate it on your network through the bonjour/avahi service.

Connect with SSH

$ ssh pi@raspberrypi.local

The password is raspberry.

For security reasons it is advisable to change the password of the user pi with the passwd command.

Optional customizations

At this point you may want to edit the hostname of the Pi. Use an editor and change the word raspberrypi to something else in:

If you are using the Pi for a headless application then you can reduce the memory split between the GPU and the rest of the system down to 16mb.

Edit /boot/config.txt and add this line:

Start the Docker installer

An automated script maintained by the Docker project will create a systemd service file and copy the relevant Docker binaries into /usr/bin/.

$ curl -sSL https://get.docker.com | sh

Until recently installing Docker on a Pi was a very manual process which often meant having to build Docker from scratch on a very underpowered device (this could take hours). Lots of hard work by ARM enthusiasts Hypriot has helped make .deb packages a first-class citizen in Docker's own CI process.

If you would like to opt into using a testing version then replace get.docker.com with test.docker.com. This will bring down a newer version but it may still have some open issues associated with it.

Beware that this work does not extend to non-Debian distributions such as Arch Linux or Fedora. Arch Linux for ARM currently has Docker 1.11 available in its package manager pacman.

Configure Docker

There are a couple of manual steps needed to get the best experience.

Set Docker to auto-start

$ sudo systemctl enable docker

You can now reboot the Pi, or start the Docker daemon with:

$ sudo systemctl start docker

Enable Docker client

The Docker client can only be used by root or members of the docker group. Add pi or your equivalent user to the docker group:

$ sudo usermod -aG docker pi

After making this change, log out and reconnect with ssh.

Using Docker

Support for ARM and the Raspberry Pi is a work-in-progress item which means there are a few things you should know.

Pulling images from the Hub

If you pull down the busybox image from the Docker hub it will not function correctly. This is because the contents are designed for a regular PC or the x86_64 architecture. There are on-going efforts to fix this in future versions of Docker.

We should only attempt to use images which we know are designed to work on ARM. At present there are no strictly official images but the Docker team maintains a number of experimental images under the prefix arm32v6.

Update 30th May 2017: the armhf account has been renamed to arm32v6 - so for future reference use the arm32v6 prefix instead.

Running your first ARM image

Let's try starting Docker's official Alpine Linux image arm32v6/alpine. Alpine Linux is a very compact 1.8MB download.

$ docker run -ti arm32v6/alpine:3.5 /bin/sh / # cat /etc/os-release NAME="Alpine Linux" ID=alpine VERSION_ID=3.5.2 PRETTY_NAME="Alpine Linux v3.5" HOME_URL="http://alpinelinux.org" BUG_REPORT_URL="http://bugs.alpinelinux.org" / # echo "Hi, this is a tiny Linux distribution!" | base64 SGksIHRoaXMgaXMgYSB0aW55IExpbnV4IGRpc3RyaWJ1dGlvbiEK / # echo "SGksIHRoaXMgaXMgYSB0aW55IExpbnV4IGRpc3RyaWJ1dGlvbiEK" | base64 -d Hi, this is a tiny Linux distribution! / # exit

Try the image and type exit when you are finished.

We launched sh - a BusyBox shell, but we could have launched any command directly.

Here's another example without using the shell - we just run the date binary directly:

$ docker run arm32v6/alpine:3.5 date Sun Mar 12 21:00:45 UTC 2017
Other base images
An image made by Resin.io is used by the current Docker build process to create a base image which is usable on all supported versions of the Raspberry Pi. It is a light-weight version of Raspbian Jessie which makes it a good choice.

Build a new image

Build your image like a regular Docker image but use resin/rpi-raspbian as your base. Let's add curl and ca-certificates and create an image which will access docker.com.

FROM resin/rpi-raspbian:latest ENTRYPOINT [] RUN apt-get update && \ apt-get -qy install curl ca-certificates CMD ["curl", "https://docker.com"]

Line-by line breakdown:

FROM - this statement is the first in the file and picks what base system to start making changes on top of

ENTRYPOINT [] - the Resin image has a pre-defined start-up instruction so this line cancels that out allow us to use our own.

RUN - each step prefixed by RUN is executed by bash. So here we install curl and common SSL certificate

CMD - this is the start-up command for the container, it's invoked by docker run

So build the image like this, and then run it:

$ docker build -t curl_docker . $ docker run curl_docker

After building an image with Docker you will see it in your library. Use the docker images command to see all the images you've built so far.

If you want to delete the curl_docker image type in: docker rmi curl_docker.
The same with Alpine Linux
Alpine Linux doesn't use apt-get to package its packages but a tool named apk, here's how to achieve the same thing:

FROM arm32v6/alpine:3.5 RUN apk add --no-cache curl ca-certificates CMD ["curl", "https://docker.com"]

To build and run the Alpine container, you can do exactly the same thing or use a different image name:

$ docker build -t curl_docker_alpine . Sending build context to Docker daemon 2.048 kB Step 1/3 : FROM arm32v6/alpine:3.5 ---> 4c5b559db95b Step 2/3 : RUN apk add --no-cache curl ca-certificates ---> Running in 68254b2889a0 fetch http://dl-cdn.alpinelinux.org/alpine/v3.5/main/armhf/APKINDEX.tar.gz fetch http://dl-cdn.alpinelinux.org/alpine/v3.5/community/armhf/APKINDEX.tar.gz (1/4) Installing ca-certificates (20161130-r0) (2/4) Installing libssh2 (1.7.0-r2) (3/4) Installing libcurl (7.52.1-r2) (4/4) Installing curl (7.52.1-r2) Executing busybox-1.25.1-r0.trigger Executing ca-certificates-20161130-r0.trigger OK: 4 MiB in 15 packages ---> ecd945783503 Removing intermediate container 68254b2889a0 Step 3/3 : CMD curl https://docker.com ---> Running in ed6a0a7afcef ---> c911937ccb69 Removing intermediate container ed6a0a7afcef Successfully built c911937ccb69 $ docker run curl_docker_alpine

Create a Node.js application

This Dockerfile uses Resin.io's Raspbian image as a base and pulls down Node 4.5 LTS from the official Node.js site.

FROM resin/rpi-raspbian:latest ENTRYPOINT [] RUN apt-get update && \ apt-get -qy install curl \ build-essential python \ ca-certificates WORKDIR /root/ RUN curl -O \ https://nodejs.org/dist/v4.5.0/node-v4.5.0-linux-armv6l.tar.gz RUN tar -xvf node-*.tar.gz -C /usr/local \ --strip-components=1 CMD ["node"]

To build and run the image:

$ docker build -t node:arm . $ docker run -ti node:arm >

You can now test out a few Node.js instructions or fork my simple hello-world microservice on Github to take it further.

> process.version 'v4.5.0' > var fs = require('fs'); > console.log(fs.readFileSync("/etc/hosts", "utf8")); > process.exit() $

Make use of GPIO

In order to make use of additional hardware and add-on boards you will need to access the GPIO pins. These require an additional flag at runtime of --privileged to allow the container to write to the special area of memory managing GPIO.

The standard RPi.GPIO library will work through Docker including the libraries from several hardware manufactures.

This is a sample Dockerfile for using the defacto RPi.GPIO library.

FROM resin/rpi-raspbian:latest ENTRYPOINT [] RUN apt-get -q update && \ apt-get -qy install \ python python-pip \ python-dev python-pip gcc make RUN pip install rpi.gpio

Build this image as a basis for adding your GPIO scripts at a later date.

$ docker build -t gpio-base .

The following Python code can be used to will blink an LED connected to GPIO pin 18.

import RPi.GPIO as GPIO import time GPIO.setmode(GPIO.BCM) led_pin = 17 GPIO.setup(led_pin, GPIO.OUT) while(True): GPIO.output(led_pin, GPIO.HIGH) time.sleep(1) GPIO.output(led_pin, GPIO.LOW) time.sleep(1)

Just use ADD to transfer the script into a new image depriving from gpio-base:

FROM gpio-base:latest ADD ./app.py ./app.py CMD ["python", "app.py"]

You will need to run this container in --privileged mode in order to be able to access the GPIO pins.

$ docker build -t blink . $ docker run -ti --privileged blink

If you enjoyed that then how about making an Internet-enabled buzzer or cheerlight? Here's an example of using the Python Flask library to create a web server that controls a GPIO pin:

Github: GPIO web server in Docker

For more on interacting with GPIO head over to the Raspberry Pi Foundation's Getting Started with Physical Computing worksheet.

Feedback & questions

Contact me via Twitter @alexellisuk or in the comments section below. What do you want to see on the blog next? Have you tried it out? Let us know!

Resin.io recently changed their base image so instead of using resin/rpi-raspbian:jessie they are suggesting we use resin/rpi-raspbian:jessie-20160831.

See also:

# data[].attributes.attachment_link.title
Get Started with Docker 1.12 on Raspberry Pi

# data[].attributes.attachment_link.description
I have put this guide together to help you get started with Docker 1.12 (or newer) on your Raspberry Pi. For simplicity we will use the default operating system for the Pi - called Raspbian. This guide currently works with most models of Raspberry Pi and I'd recommending using the Model B 2/3 or Zero.

# data[].attributes.attachment_link.readable_text
Managing several Raspberry Pi can be a lot of work. This article will teach you how Kubernetes and Docker will make your life easier.
Foreword

I own 4 Raspberry Pi and I got interested in Kubernetes when I was tired of managing my Raspberry Pi and keeping track of what was installed and running on which machine.

Using Docker containers allows me to make sure my applications are packaged with their dependencies. Kubernetes is a platform that manages containers on hosts. It allocates the containers on the available Raspberry Pi. I can pull out one of them to do something else, and when I'm done, I add it back into the cluster.

Install Kubernetes on Raspberry Pi

For this step, I won't reinvent the wheel. A tutorial has been made to install Kubernetes on the Raspberry Pi. This gist is updated on a regular basis to keep up with any breaking changes.

This can be tedious because you have to repeat some steps (like burning the SD cards, install Docker, etc.) for each Raspberry Pi. It took around an hour for four machines.

Read carefully, some steps are to be performed on the master node only and others are to be performed on all the nodes (or all the slave nodes).

The only thing that didn't work as mentioned in the tutorial is getting the 3/3 Running on the kube-dns pods. It only showed 3/3 Running after I launched the command.

$ kubectl apply -f \
 "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"

Take your time to get it working. I'll wait for you.

If you don't have a cluster of Raspberry Pi available but you still want to try Kubernetes on one machine, you can use Minikube.

Hello world example

Maybe you didn't notice but if you followed the tutorial to install Kubernetes on Raspbian, you ran an elaborate Hello world example when you executed

kubectl create -f function.yml

Take a look at the function.yml file. There are two files in the file. You created a service which maps the port 8080 of your pod to the port 31118 of your cluster. You also created a deployment of one pod from the Docker image functions/markdownrender:latest-armhf exposing an API on port 8080. Your API is now available on port 31118 from outside of the cluster.

You interact with Kubernetes with the kubectl command. Here you read a configuration file and create the objects described in the file.

Pods are the base unit of Kubernetes. It can contain containers and volumes. All containers within a pod share the same port space and IP address (they can find each other on localhost).

Deployments are a way to manage multiple pods together (for example replications of the same pod). They are the preferred way of managing the state of the cluster (e.g. "I want 3 replicas of this pod from that image).

Services are the network interfaces of the pods. It allows mapping the port of the pods to external port. They also act as load balancers when you use replicas.
There are a lot of different objects corresponding to different functionalities (like jobs, configuration, replication, etc.).

Use cases

Home server

I use my cluster as a home server to host applications. For example, it serves as a backend for my humidity and temperature monitoring sensors, following a water damage in my apartment. I log my data in InfluxDB and plot them with Grafana. Kubernetes answers my problem because:

InfluxDB and Grafana each run in a pod with the default settings from the default Docker images. I had nothing to configure to set them up (except using InfluxDB as the data source in the Grafana GUI).

I can use my NAS as a NFS volume that I can mount on my pods. I don't run the risk of wiping the data because of an accidental SD car wiping.

I can run the app privately without having to implement an auth system.

Again, my data is on my NAS and I don't run the risk of losing it.

I also have deployed some applications like my burndown chart app that I use to track my goals. Before that, I was using Heroku on the free tier but the application was slow to start and it was public. Now:

Experiments with distributed systems

My other use case with my cluster is the experimentation with distributed systems. What happens if I launch two MySQL pods on the same data volume? How many messages/second can I send through RabbitMQ? Is it easy to set up Consul? How fast is eventual consistency in Cassandra?

You can deploy an image in a few lines of configuration and set up your experiments.

# data[].attributes.attachment_link.title
Build Your Own Cloud with Kubernetes and Some Raspberry Pi

# data[].attributes.attachment_link.description
Managing several Raspberry Pi can be a lot of work. This article will teach you how Kubernetes and Docker will make your life easier. I own 4 Raspberry Pi and I got interested in Kubernetes when I was tired of managing my Raspberry Pi and keeping track of what was installed and running on which machine.

# data[].attributes.attachment_link.readable_text
Apparently it's that time of the year again. Approximately a year ago I published a "state-of-the-art" how to run a Raspberry Pi Kubernetes cluster using HypriotOS and Kubernetes 1.4. Lots of things has happen during the past year, and I thought it was time to play with the Raspberry Pi cluster again. This blog post will guide you through the process of setting up a Raspberry Pi Kubernetes cluster on the latest version of Raspbian, and with the latest version of Kubernetes, which is 1.9.0.

This blog post was inspired by the great work of Docker Captain Alex Ellis.

Let's get started!

Initial setup of SD-cards and prerequisites

The following section is pretty generic. This flow has to be repeated for every node you want to join your cluster.

Flashing the SD card

The first thing we need is an image. Grab the latest Raspbian OS here (.zip).
I use etcher by Resin.io for flashing the SD-cards. It doesn't get easier than this.

Just select the .zip file you just downloaded, and insert your SD-card, select the drive, and click "Flash!". Easy, right?

Once the flashing process is finished, we need to add an empty file to the drive. Therefore, take the SD-card out and insert it again. We are going to create an empty file called ssh. This allow us to SSH into the node once booted.

$ touch /Volumes/boot/ssh

Now, take out the SD-card and insert it into the Raspberry Pi. Attach network cable and power, and boot up the little machine.

After a minute or so, you should be able to access the Raspberry Pi from the same network.

$ ssh pi@raspberrypi.local

Default raspbian password is: raspberry

Change the hostname and assign a static IP

Next, we will configure the Raspberry Pi, so that it's easy to identify and access. We will therefore change the hostname, and assign a static IP to the node. In order to make this process a bit easier, I have made a simple script for you.

In order to run it, create a new file on the Pi:

$ nano hostname_and_ip.sh

Copy the following into the new file

And run the script (below is the naming and IP convention used in my setup, you should adapt this to your network setup)

First argument: the new hostname
Second argument: the new static IP
Third argument: the IP of your Router
master: 192.168.1.100
$ sh hostname_and_ip.sh master 192.168.1.100 192.168.1.1
worker-01: 192.168.1.101
$ sh hostname_and_ip.sh worker-01 192.168.1.101 192.168.1.1
worker-02: 192.168.1.102
$ sh hostname_and_ip.sh worker-02 192.168.1.102 192.168.1.1
worker-03: 192.168.1.103
$ sh hostname_and_ip.sh worker-03 192.168.1.103 192.168.1.1

Now, reboot the Pi. You should be able to access the Pi over SSH as follows:

$ ssh pi@master.local (or worker-01.local etc.)

Verify that your Pi now also has a new static ip by running ifconfig.

Installing the prerequisites

Now, that node networking and naming is in place, we need to install some software on the Raspberry Pi. First of all we need docker, secondly we need to add the kubernetes repo to the repo list, disable swap memory, and lastly install kubeadm. Again, in order to make this process easy for you as a reader, all of this can be run as a script.

Therefore, create a new file on the Raspberry Pi:

$ nano init.sh

Copy and insert the following script.
I experienced some issues with a change in the kernel related to cgroups_memory. The current solution is reflected in the script above. However, if you encounter issues, you might want to change cgroup_memory=1 to cgroup_enable=memory. For now, however, cgroup_memory=1 is working. More on this can be found .
Run the script,

$ sh init.sh

Reboot the machine and SSH back into the Raspberry Pi once the reboot has finished.

$ sudo reboot

That was all the prerequisites and generic setup of all the Raspberry Pis. Remember to repeat this process for every node in the cluster.

Now, let's move on to setting up our Kubernetes master.

Initialize the Kubernetes master

So, we are now ready to set up Kubernetes. To do this, we are going to use the awesome tool called, kubeadm. This makes it pretty easier to spin up a Kubernetes cluster by, basically, running kubeadm init on the master node and kubeadm join on the worker nodes.

One of the purposes of this cluster is going to be demoing Kubernetes stuff. One example could be to pull out the network cable of one of the worker nodes and demoing how Kubernetes deals with this situation by rescheduling the pods from the lost node.

Therefore, we would like to change one of the arguments to the kube-controller-manager, namely, pod-eviction-timeout which defaults to 5 minutes. That's a long time to wait in a presentation. Instead, we want to change this to 10s.

Changing arguments passed to the different Kubernetes core components by kubeadm is pretty simple. We just have to pass a YAML configuration file specifying the arguments we want to change. Let's do that.

Create the configuration file:

$ nano kubeadm_conf.yaml

Copy and insert the following

apiVersion: kubeadm.k8s.io/v1alpha1
kind: MasterConfiguration
controllerManagerExtraArgs:
 pod-eviction-timeout: 10s

You may wish to change the time that Kubernetes allows the node to be unresponsive as well. It defaults to 40 seconds. To change this, add the following argument to the master configuration above: node-monitor-grace-period: 10s.

Save and run

$ sudo kubeadm init --config kubeadm_conf.yaml

This takes a couple of minutes. Once the process finishes you should see something similar to:

...

Your Kubernetes master has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
 sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
 sudo chown $(id -u):$(id -g) $HOME/.kube/config

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
 https://kubernetes.io/docs/concepts/cluster-administration/addons/

You can now join any number of machines by running the following on each node
as root:

kubeadm join --token TOKEN 192.168.1.100:6443 --discovery-token-ca-cert-hash HASH

Follow the instructions in the output:

$ mkdir -p $HOME/.kube
$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
$ sudo chown $(id -u):$(id -g) $HOME/.kube/config

You can verify that your master node is up and running.

pi@master:~ $ kubectl get nodes
NAME STATUS ROLES AGE VERSION
master NotReady master 3m v1.9.0

Don't mind the status being NotReady. In order for the master node to become ready we need to install a container network. But before we do that, let's add some more nodes to the cluster first.

Setting up the worker nodes

Alright, next up we need to spin up some workers for the cluster to be complete.

Assuming you have already set up the prerequisuites mentioned above, we basically only need to run the kubeadm join on each of your worker nodes. As shown above, kubeadm outputs the command that you need to run on all your worker nodes.

$ sudo kubeadm join --token TOKEN 192.168.1.100:6443 --discovery-token-ca-cert-hash HASH

Repeat for every node.

Set up the container network

Nodes are not able to communicate without a container network, which is something you have to provide. Therefore, the final piece of the puzzle is to add one. We will be using weave-net for this. On the master node, run the following command:

$kubectl apply -f https://git.io/weave-kube-1.6

All set and done...

That was it. You should now have a fully functioning Raspberry Pi Kubernetes cluster. Verify your setup by running

pi@master:~ $ kubectl get nodes
NAME STATUS ROLES AGE VERSION
master Ready master 55m v1.9.0
worker-01 Ready <none> 34m v1.9.0
worker-02 Ready <none> 14m v1.9.0
worker-03 Ready <none> 5m v1.9.0

Last thing we need to verify is that the configuration of the controller-manager we specified earlier. Did the pod-eviction-timeout get parsed to the actual kube-controller-manager process? This is easy to test, just run

$ kubectl describe pod kube-controller-manager-master -n kube-system

You should see something similar to this

...
...
Containers:
 kube-controller-manager:
 Container ID: docker://f9f4077d9008690f04169932c02fba79c8d446b71a347f75c2f6aa96f36587ca
 Image: gcr.io/google_containers/kube-controller-manager-arm:v1.9.0
 Image ID: docker-pullable://gcr.io/google_containers/kube-controller-manager-arm@sha256:167a5468244114c484856bfe995cc3630678f0ab2aa85cf9d1ab6341fd04b8e5
 Port: <none>
 Command:
 kube-controller-manager
 --pod-eviction-timeout=10s
 --kubeconfig=/etc/kubernetes/controller-manager.conf
 --service-account-private-key-file=/etc/kubernetes/pki/sa.key
 --cluster-signing-cert-file=/etc/kubernetes/pki/ca.crt
 --cluster-signing-key-file=/etc/kubernetes/pki/ca.key
 --address=127.0.0.1
 --leader-elect=true
 --use-service-account-credentials=true
 --controllers=*,bootstrapsigner,tokencleaner
 --root-ca-file=/etc/kubernetes/pki/ca.crt
 State: Running
 Started: Wed, 20 Dec 2017 18:52:13 +0000
 Ready: True
 Restart Count: 0
...
...

As you can see the parameter was passed correctly to the kube-controller-manager.

That was all for this time folks. Happy hacking.

# data[].attributes.attachment_link.title
Setup a Kubernetes 1.9.0 Raspberry Pi cluster on Raspbian using Kubeadm

# data[].attributes.attachment_link.description
Apparently it's that time of the year again. Approximately a year ago I published a "state-of-the-art" how to run a Raspberry Pi Kubernetes cluster using HypriotOS and Kubernetes 1.4. Lots of things has happen during the past year, and I thought it was time to play with the Raspberry Pi cluster again.

# data[].attributes.attachment_link.description
Create a new spreadsheet and edit with others at the same time -- from your computer, phone or tablet. Get stuff done with or without an internet connection. Use Sheets to edit Excel files. Free from Google.

# data[].attributes.attachment_link.description
Create a new document and edit with others at the same time -- from your computer, phone or tablet. Get stuff done with or without an internet connection. Use Docs to edit Word files. Free from Google.

# data[].attributes.attachment_link.description
A visualizer for Docker Swarm Mode using the Docker Remote API, Node.JS, and D3 - ManoMarks/docker-swarm-visualizer

# data[].attributes.attachment_link.readable_text
Kubernetes and Docker Swarm are probably two most commonly used tools to deploy containers inside a cluster. Both are created as helper tools that can be used to manage a cluster of containers and treat all servers as a single unit. However, they differ greatly in their approach.

Kubernetes

Kubernetes is based on Google's experience of many years working with Linux containers. It is, in a way, a replica of what Google has been doing for a long time but, this time, adapted to Docker. That approach is great in many ways, most important being that they used their experience from the start. If you started using Kubernetes around Docker version 1.0 (or earlier), the experience with Kubernetes was great. It solved many of the problems that Docker itself had. We could mount persistent volumes that would allow us to move containers without loosing data, it used flannel to create networking between containers, it has load balancer integrated, it uses etcd for service discovery, and so on. However, Kubernetes comes at a cost. It uses a different CLI, different API and different YAML definitions. In other words, you cannot use Docker CLI nor you can use Docker Compose to define containers. Everything needs to be done from scratch exclusively for Kubernetes. It's as if the tool was not written for Docker (which is partly true). Kubernetes brought clustering to a new level but at the expense of usability and steep learning curve.

Docker Swarm

Docker Swarm took a different approach. It is a native clustering for Docker. The best part is that it exposes standard Docker API meaning that any tool that you used to communicate with Docker (Docker CLI, Docker Compose, Dokku, Krane, and so on) can work equally well with Docker Swarm. That in itself is both an advantage and a disadvantage at the same time. Being able to use familiar tools of your own choosing is great but for the same reasons we are bound by the limitations of Docker API. If the API doesn't support something, there is no way around it through Swarm API and some clever tricks need to be performed.

We'll explore those two tools in more details based on their setup and features they provide for running containers in a cluster.

Setting Up

Setting up Docker Swarm is easy, straightforward and flexible. All we have to do is install one of the service discovery tools and run the swarm container on all nodes. Since the distribution itself is packed as a Docker container, it works in the same way no matter the operating system. We run the swarm container, expose a port and inform it about the address of the service discovery. It could hardly be easier than that. We can even start using it without any service discovery tool, see whether we like it and when our usage of it becomes more serious, add etcd, Consul or some of the other supported tools.

Kubernetes setup is quite more complicated and obfuscated. Installation instructions differ from OS to OS and provider to provider. Each OS or a hosting provider comes with its own set of instructions each of them having a separate maintenance team with a separate set of problems. As example, if you choose to try it out with Vagrant, you are stuck with Fedora. That does not mean that you cannot run it with Vagrant and, let's say, Ubuntu or CoreOS. You can, but you need to start searching for instructions outside the official Kubernetes Getting Started page. Whatever your needs are, it's likely that the community has the solution but you still need to spend some time searching for it and hoping that it works from the first attempt. The bigger problem is that the installation relies on a bash script. That would not be a big deal in itself if we would not live in the era where configuration management is a must. We might not want to run a script but make Kubernetes be part of our Puppet, Chef or Ansible definitions. Again, this can be overcome as well. You can find Ansible playbooks for running Kubernetes or you can write your own. None of those issues are a big problem but, when compared with Swarm, they are a bit painful. With Docker we were supposed not to have installation instructions (aside from a few docker run arguments). We were supposed to run containers. Swarm fulfils that promise and Kubernetes doesn't.

While some might not care about which discovery tool is used, I love the simplicity behind Swarm and the logic "batteries included but removable". Everything works out-of-the-box but we still have the option to substitute one component with the other. Unlike Swarm, Kubernetes is opinionated tool. You need to live with the choices it made for you. If you want to use Kubernetes, you have to use etcd. I'm not trying to say that etcd is bad (quite contrary) but if you prefer, for example, to use Consul you're in a very complicated situation and would need to use one for Kubernetes and the other for the rest of your service discovery needs. Another thing I dislike about Kubernetes is its need to know things in advance, before the setup. You need to tell it the addresses of all your nodes, which role each of them has, how many minions there are in the cluster and so on. With Swarm, we just bring up a node and tell it to join the network. Nothing needs to be set in advance since the information about the cluster is propagated through gossip.

Set up might not be the most important difference between those tools. No matter which tool you choose, sooner or later everything will be up and running and you'll forget any trouble you might have had during the process. You might say that we should not choose one tool over the other only because one is easier to set up. Fair enough. Let's move on and speak about differences in how you define containers that should be run with those tools.

Running Containers

How do you define all the arguments needed for running Docker containers with Swarm? You don't! Actually, you do but not in any form or way different from the way you were defining them before Swarm. If you are used to run containers through Docker CLI, you can continue using it with (almost) the same commands. If you prefer to use Docker Compose to run containers, you can continue using it to run them inside the Swarm cluster. Whichever way you're used to run your containers, chances are that you can continue doing the same with Swarm but on a much larger scale.

Kubernetes requires you to learn its CLI and configurations. You cannot use docker-compose.yml definitions you created earlier. You'll have to create Kubernetes equivalents. You cannot use Docker CLI commands you learned before. You'll have to learn Kubernetes CLI and, likely, make sure that the whole organization learns it as well.

No matter which tool you choose for deployments to your cluster, chances are you are already familiar with Docker. You are probably already used to Docker Compose as a way to define arguments for the containers you'll run. If you played with it for more than a few hours, you are using it as a substitute for Docker CLI. You run containers with it, tail their logs, scale them, and so on. On the other hand, you might be a hard-core Docker user who does not like Docker Compose and prefer running everything through Docker CLI or you might have your own bash scripts that run containers for you. No matter what you choose, it should work with Docker Swarm.

If you adopt Kubernetes, be prepared to have multiple definitions of the same thing. You will need Docker Compose to run your containers outside Kubernetes. Developers will continue needing to run containers on their laptops, your staging environments might or might not be a big cluster, and so on. In other words, once you adopt Docker, Docker Compose or Docker CLI are unavoidable. You have to use them one way or another. Once you start using Kubernetes you will discover that all your Docker Compose definitions (or whatever else you might be using) need to be translated to Kubernetes way of describing things and, from there on, you will have to maintain both. With Kubernetes everything will have to be duplicated resulting in higher cost of maintenance. And it's not only about duplicated configurations. Commands you'll run outside of the cluster will be different from those inside the cluster. All those Docker commands you learned and love will have to get their Kubernetes equivalents inside the cluster.

Guys behind Kubernetes are not trying to make your life miserable by forcing you to do things "their way". The reason for such big differences is in a different approaches Swarm and Kubernetes are using to tackle the same problem. Swarm team decided to match their API with the one from Docker. As a result, we have (almost) full compatibility. Almost everything we can do with Docker we can do with Swarm as well only on a much larger scale. There's nothing new to do, no configurations to be duplicated and nothing new to learn. No matter whether you use Docker CLI directly or go through Swarm, API is (more or less) the same. The negative side of that story is that if there is something you'd like Swarm to do and that something is not part of the Docker API, you're in for a disappointment. Let us simplify this a bit. If you're looking for a tool for deploying containers in a cluster that will use Docker API, Swarm is the solution. On the other hand, if you want a tool that will overcome Docker limitations, you should go with Kubernetes. It is power (Kubernetes) against simplicity (Swarm). Or, at least, that's how it was until recently. But, I'm jumping ahead of myself.

The only question unanswered is what those limitations are. Two of the major ones were networking and persistent volumes. Until Docker Swarm release 1.0 we could not link containers running on different servers. Actually, we still cannot link them but now we have multi-host networking to help us connect containers running on different servers. It is a very powerful feature. Kubernetes used flannel to accomplish networking and now, since the Docker release 1.9, that feature is available as part of Docker CLI.

Another problem were persistent volumes. Docker introduced them in release 1.9. Until recently, if you persist a volume, that container was tied to the server that volume resides. It could not be moved around without, again, resorting to some nasty tricks like copying volume directory from one server to another. That in itself is a slow operation that defies the goals of tools like Swarm. Besides, even if you have time to copy a volume from one to the other server, you do not know where to copy since clustering tools tend to treat your whole datacenter as a single entity. You containers will be deployed to a location most suitable for them (least number of containers running, most CPUs or memory available, and so on). Now we have persistent volumes supported by Docker natively.

Both networking and persistent volumes problems were one of the features supported by Kubernetes for quite some time and the reason why many were choosing it over Swarm. That advantage disappeared with Docker release 1.9.

The Choice

When trying to make a choice between Docker Swarm and Kubernetes, think in following terms. Do you want to depend on Docker itself solving problems related to clustering. If you do, choose Swarm. If something is not supported by Docker it will be unlikely that it will be supported by Swarm since it relies on Docker API. On the other hand, if you want a tool that works around Docker limitations, Kubernetes might be the right one for you. Kubernetes was not built around Docker but is based on Google's experience with containers. It is opinionated and tries to do things in its own way.

The real question is whether Kubernetes' way of doing things, which is quite different from how we use Docker, is overshadowed by advantages it gives. Or, should we place our bets into Docker itself and hope that it will solve those problems? Before you answer those questions, take a look at the release 1.9. We got persistent volumes and software networking. We also got unless-stopped restart policy that will manage our unwanted failures. Now there are three things less of a difference between Kubernetes and Swarm. Actually, these days there are very few advantages Kubernetes has over Swarm. On the other hand, Swarm uses Docker API meaning that you get to keep all your commands and Docker Compose configurations. Personally, I'm placing my bets on Docker engine getting improvements and Docker Swarm running on top of it. The difference between the two is very small. Both are production ready but Swarm is easier to set up, easier to use and we get to keep everything we built before moving to the cluster; there is no duplication between cluster and non-cluster configurations.

My recommendation is to go with Docker Swarm. Kubernetes is too opinionated, hard to set up, too different from Docker CLI/API and at the same time it doesn't have real advantages over Swarm since the Docker release 1.9. That doesn't mean that there are no features available in Kubernetes that are not supported by Swarm. There are feature differences in both directions. However, those differences are, in my opinion, not major ones and the gap is getting smaller with each Docker release. Actually, for many use cases there is no gap at all while Docker Swarm is easier to set up, learn and use.

# data[].attributes.attachment_link.title
Docker Clustering Tools Compared: Kubernetes vs Docker Swarm

# data[].attributes.attachment_link.description
Kubernetes and Docker Swarm are probably two most commonly used tools to deploy containers inside a cluster. Both are created as helper tools that can be used to manage a cluster of containers and treat all servers as a single unit. However, they differ greatly in their approach.

# data[].attributes.body
These Docker Images are configured with Tomcat Manager enabled.

# data[].attributes.headline
How I setup a Raspberry Pi 3 Cluster Using The New Docker Swarm Mode In 29 Minutes

# data[].attributes.subject
How I setup a Raspberry Pi 3 Cluster Using The New Docker Swarm Mode In 29 Minutes

# data[].attributes.attachment_link.title
How I setup a Raspberry Pi 3 Cluster Using The New Docker Swarm Mode In 29 Minutes

# data[].attributes.headline
How to run a Raspberry Pi cluster with Docker Swarm

# data[].attributes.subject
How to run a Raspberry Pi cluster with Docker Swarm

# data[].attributes.attachment_link.title
How to run a Raspberry Pi cluster with Docker Swarm

# data[].attributes.body
From Overview Presentation

# data[].attributes.body
Very early draft

# data[].attributes.body
Very early draft

# data[].attributes.body
As published on GitHub

# data[].attributes.body
Docker Swarm Setup Notes

# data[].attributes.headline
Demystifying the Data Volume / Storage in Docker

# data[].attributes.subject
Demystifying the Data Volume / Storage in Docker

# data[].attributes.attachment_link.title
Demystifying the Data Volume : Storage in Docker

# data[].attributes.headline
Managing Persistence for Docker Containers

# data[].attributes.subject
Managing Persistence for Docker Containers

# data[].attributes.attachment_link.title
Managing Persistence for Docker Containers

# data[].attributes.attachment_link.title
Raspberry Pi microSD card performance comparison - 2018 | Jeff Geerling

# data[].attributes.attachment_link.title
Increasing RAM Capacity on Raspberry Pi using zRAM. Does It Work?

# data[].attributes.body
Submitted Version

# data[].attributes.body
The following summarizes the performance testing results after adding a faster SD Card and enabling zRam.

1. The Samsung Evo Plus SD Card has the potential to improve performance by 10-30%.

2. Enabling zRam did not have any perceivable impact on improving performance and might have reduced performance.

# data[].attributes.attachment_link.readable_text
If you're not already familiar with Docker, it's a method of packaging software to include not only your code, but also other components such as a full file system, system tools, services, and libraries. You can then run the software on multiple machines without a lot of setup. Docker calls these packages containers.

Think of it like a shipping container and you've got some idea of how it works. Shipping containers are a standard size so that they can be moved around at ports, and shipped via sea or land. They can also contain almost anything. Docker containers can hold your software's code and its dependencies, so that it can easily run on many different machines. Developers often use them to create a web application server that runs on their own machine for development, and is then pushed to the cloud for the public to use.

While we've noticed people using Docker on Raspberry Pi for a while now, the latest release officially includes Raspbian Jessie installation support. You can now install the Docker client on your Raspberry Pi with just one terminal command:
curl -sSL https://get.docker.com | sh
From there, you can create your own container or download pre-made starter containers for your projects. The documentation is thorough and easy to follow. You can also follow this Pi-focused guide by Docker captain Alex Ellis.

Docker Swarm

One way you can use Raspberry Pi and Docker together is for Swarm. Used together, they can create a computer cluster. With Swarm containers on a bunch of networked Raspberry Pis, you can build a powerful machine and explore how a Docker Swarm works. Alex shows you how in this video:

Get all the details @ http://blog.alexellis.io/live-deep-dive-pi-swarm/

You can follow along with Alex's written tutorial as well. He has even taken it further by using Pi Zero's USB gadget capabilities to create a tiny Docker Swarm:

Look ma, no Ethernet! 8 core @Docker 1.12 swarm boom USB OTG @Raspberry_Pi @pimoroni

The Raspberry Pi already makes many computing tasks easier; why not add deploying remote applications to that list with Docker?

# data[].attributes.attachment_link.title
Docker comes to Raspberry Pi - Raspberry Pi

# data[].attributes.attachment_link.description
If you're not already familiar with Docker, it's a method of packaging software to include not only your code, but also other components such as a full file system, system tools, services, and libraries. You can then run the software on multiple machines without a lot of setup.

# data[].attributes.headline
How to get started using Docker and Docker Swarm

# data[].attributes.subject
How to get started using Docker and Docker Swarm

# data[].attributes.attachment_link.title
HOWTO - Getting Started with Docker and Docker Swarm

# data[].attributes.attachment_link.readable_text
# Install Docker
curl -sSL https://get.docker.com | sh

# Add a Docker Group (to use Docker as a non-root user)
sudo usermod -aG docker pi

# Enable Docker on Startup or start manually using the command 'sudo systemctl start docker'
sudo systemctl enable docker

# Restart the Pi to validate that Docker is running on Startup then test Docker by running the following
docker run arm32v6/alpine:3.5 date			# Run the Date command from the Alpine Linux image
docker run -ti arm32v6/alpine:3.5 /bin/sh	# Run a shell from the Alpine Linux image

# Some common Linux base images for Pi and Arm64
resin/rpi-raspbian:latest
arm32v6/alpine:3.5

# Some commonly used Docker commands:
docker ps -as					# Display all Docker Containers
docker images					# Display all images from the Docker Library
docker build -t [Image Name] .	# Build a Docker Image
docker run [Image Name]			# Run a Docker Image
docker rm [Container ID]		# Delete a Docker Container
docker rmi [Image Name]			# Delete a Docker Image from the Docker Library
# Stop and remove all Containers
docker stop $(docker ps -a -q)
docker rm $(docker ps -a -q)

# Create some Test Dockerfiles
1. Create a Folder on the Desktop called DockerPlay
2. Create a Folder in the DockerPlay folder called ShellTest
3. Create a file called Dockerfile, add the following command to it, and save the file
	FROM arm32v6/alpine:3.5
	CMD ['/bin/sh']
4. Open a Terminal and navigate to the DateTest folder. Build and run the Docker Image:
	docker build -t shelltest .
	docker run shelltest 
	
======================================================================
	
# RDP Ideas
Build the following Docker Containers: Tomcat, JBoss, PHP Web Server, MySQL, PostgreSQL, Python (with AI), NodeJS (prebuilt Docker Images)
Build a Web Application that allows a user to provision a desired Container
	- User can select a Container from the Catalog
	- A pre-built Docker Image will then be run using docker run
	- The user can start, stop, configure, and destroy a Container
	- Docker Swarm or Kubernetes will be used to cluster the Containers across a farm of Pi's 
Assign a Container across members of the RDP team and document how the container is started, configured, and tested (either use Docker Hub images or create our own Dockerfile).
Assign a RDP team member to help architect the Pi Cloud Interface (a bunch of REST API's).
Assign a RDP team member to help architect a Pi "install script to install docker, configure docker, and start the Cloud Interface).
Assign a RDP team member to help architect the GCU Cloud Management Application.

# Run Tomcat and test at http://localhost:8080
docker run -it --rm -p 8080:8080 tomcat:8.5
# Run Tomcat on smaller Alpine base image using the tomcat:<version>-alpine image
docker run -it --rm -p 8080:8080 tomcat:8.5-alpine

# Run MySQL (MariaDB) where some-mariadb is the name you want to assign to your container, my-secret-pw is the password to be set for the MySQL root user and tag is the tag specifying the MySQL version you want.
# See https://hub.docker.com/_/mariadb/ for how to connect CLI or connect to another docker application 
docker run --name some-mariadb -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mariadb:tag

# Run PHP and Apache Web Server
docker run -d -p 80:80 --name my-apache-php-app -v "$PWD":/var/www/html php:7.2-apache

# Some good resources and images from Docker Hub
https://github.com/alexellis/docker-arm
https://hub.docker.com/_/tomcat/
https://hub.docker.com/r/project31/aarch64-jboss-base/
https://hub.docker.com/_/mariadb/
https://hub.docker.com/_/php/

# data[].attributes.attachment_link.readable_text
In this article, we take a look at another well-established platform specific API - Java API Client for Docker.

Throughout the article, we comprehend the way of how to connect with a running Docker daemon and what type of important functionality the API offers to Java developers.

2. Maven Dependency

First, we need to add the main dependency into our pom.xml file:

<dependency>
    <groupId>com.github.docker-java</groupId>
    <artifactId>docker-java</artifactId>
    <version>3.0.14</version>
</dependency>

At the time of writing the article, the latest version of the API is 3.0.14. Each release can be viewed either from the GitHub release page or from the Maven repository.

3. Using the Docker Client

DockerClient is where we can establish a connection between a Docker engine/daemon and our application.

By default, the Docker daemon can only be accessible at the unix:///var/run/docker.sock file. We can locally communicate with the Docker engine listening on the Unix socket unless otherwise configured.

Here, we apply to the DockerClientBuilder class to create a connection by accepting the default settings:

DockerClient dockerClient = DockerClientBuilder.getInstance().build();

Similarly, we can open a connection in two steps:

DefaultDockerClientConfig.Builder config
  = DefaultDockerClientConfig.createDefaultConfigBuilder();
DockerClient dockerClient = DockerClientBuilder
  .getInstance(config)
  .build();

Since engines could rely on other characteristics, the client is also configurable with different conditions.

For example, the builder accepts a server URL, that is, we can update the connection value if the engine is available on port 2375:

DockerClient dockerClient
  = DockerClientBuilder.getInstance("tcp://docker.baeldung.com:2375").build();

Note that we need to prepend the connection string with unix:// or tcp:// depending on the connection type.

If we go one step further, we can end up with a more advanced configuration using the DefaultDockerClientConfig class:

DefaultDockerClientConfig config
  = DefaultDockerClientConfig.createDefaultConfigBuilder()
    .withRegistryEmail("[email protected]") .withRegistryPassword("baeldung") .withRegistryUsername("baeldung") .withDockerCertPath("/home/baeldung/.docker/certs") .withDockerConfig("/home/baeldung/.docker/") .withDockerTlsVerify("1") .withDockerHost("tcp://docker.baeldung.com:2376").build(); DockerClient dockerClient = DockerClientBuilder.getInstance(config).build();

Likewise, we can carry out the same approach using Properties:

Properties properties = new Properties();
properties.setProperty("registry.email", "[email protected]"); properties.setProperty("registry.password", "baeldung"); properties.setProperty("registry.username", "baaldung"); properties.setProperty("DOCKER_CERT_PATH", "/home/baeldung/.docker/certs"); properties.setProperty("DOCKER_CONFIG", "/home/baeldung/.docker/"); properties.setProperty("DOCKER_TLS_VERIFY", "1"); properties.setProperty("DOCKER_HOST", "tcp://docker.baeldung.com:2376"); DefaultDockerClientConfig config = DefaultDockerClientConfig.createDefaultConfigBuilder() .withProperties(properties).build(); DockerClient dockerClient = DockerClientBuilder.getInstance(config).build();

Another choice unless we configure the engine's settings in the source code is to set corresponding environment variables so that we can only consider the default instantiation of DockerClient in the project:

export DOCKER_CERT_PATH=/home/baeldung/.docker/certs
export DOCKER_CONFIG=/home/baeldung/.docker/
export DOCKER_TLS_VERIFY=1
export DOCKER_HOST=tcp://docker.baeldung.com:2376

4. Container Management

The API allows us a variety of choices about container management. Let's look at each one of them.

4.1. List Containers

Now that we have an established connection, we can list all the running containers located on the Docker host:

List<Container> containers = dockerClient.listContainersCmd().exec();

Provided that showing the running containers doesn't appeal the need, we can make use of the offered options to query containers.

In this case, we display containers with the "exited" status:

List<Container> containers = dockerClient.listContainersCmd()
  .withShowSize(true)
  .withShowAll(true)
  .withStatusFilter("exited").exec()

It's an equivalent of:

$ docker ps -a -s -f status=exited
# or
$ docker container ls -a -s -f status=exited

4.2. Create a Container

Creating a container is served with the createContainerCmd method. We can declare more complex declaration using the available methods starting with the "with" prefix.

Let's assume that we have a docker create command defining a host-dependent MongoDB container listening internally on port 27017:

$ docker create --name mongo \
  --hostname=baeldung \
  -e MONGO_LATEST_VERSION=3.6 \
  -p 9999:27017 \
  -v /Users/baeldung/mongo/data/db:/data/db \
  mongo:3.6 --bind_ip_all

We're able to bootstrap the same container along with its configurations programmatically:

CreateContainerResponse container
  = dockerClient.createContainerCmd("mongo:3.6")
    .withCmd("--bind_ip_all")
    .withName("mongo")
    .withHostName("baeldung")
    .withEnv("MONGO_LATEST_VERSION=3.6")
    .withPortBindings(PortBinding.parse("9999:27017"))
    .withBinds(Bind.parse("/Users/baeldung/mongo/data/db:/data/db")).exec();

4.3. Start, Stop, and Kill a Container

Once we create the container, we can start, stop and kill it by name or id respectively:

dockerClient.startContainerCmd(container.getId()).exec();

dockerClient.stopContainerCmd(container.getId()).exec();

dockerClient.killContainerCmd(container.getId()).exec();

4.4. Inspect a Container

The inspectContainerCmd method takes a String argument which indicates the name or id of a container. Using this method, we can observe the metadata of a container directly:

InspectContainerResponse container
  = dockerClient.inspectContainerCmd(container.getId()).exec();

4.5. Snapshot a Container

Similar to the docker commit command, we can create a new image using the commitCmd method.

In our example, the scenario is, we previously run an alpine:3.6 container whose id is "3464bb547f88" and installed git on top of it.

Now, we want to create a new image snapshot from the container:

String snapshotId = dockerClient.commitCmd("3464bb547f88")
  .withAuthor("Baeldung <[email protected]>") .withEnv("SNAPSHOT_YEAR=2018") .withMessage("add git support") .withCmd("git", "version") .withRepository("alpine") .withTag("3.6.git").exec();

Since our new image bundled with git remains on the host, we can search it on the Docker host:

$ docker image ls alpine --format "table {{.Repository}} {{.Tag}}"
REPOSITORY TAG
alpine     3.6.git

5. Image Management

There are a few applicable commands we are given to manage image operations.

5.1. List Images

To list all the available images including dangling images on the Docker host, we need to apply to the listImagesCmd method:

List<Image> images = dockerClient.listImagesCmd().exec();

If we have two images on our Docker Host, we should obtain the Image objects of them at run-time. The images we look for are:

$ docker image ls --format "table {{.Repository}} {{.Tag}}"
REPOSITORY TAG
alpine     3.6
mongo      3.6

Next to this, to see the intermediate images, we need to request it explicitly:

List<Image> images = dockerClient.listImagesCmd()
  .withShowAll(true).exec();

If only displaying the dangling images is the case, the withDanglingFilter method must be considered:

List<Image> images = dockerClient.listImagesCmd()
  .withDanglingFilter(true).exec();

5.2. Build an Image

Let's focus on the way of building an image using the API. The buildImageCmd method builds Docker images from a Dockerfile. In our project, we already have one Dockerfile which gives an Alpine image with git installed:

FROM alpine:3.6

RUN apk --update add git openssh && \
  rm -rf /var/lib/apt/lists/* && \
  rm /var/cache/apk/*

ENTRYPOINT ["git"]
CMD ["--help"]

The new image will be built without using cache and before starting the building process, in any case, Docker engine will attempt to pull the newer version of alpine:3.6. If everything goes well, we should eventually see the image with the given name, alpine:git:

String imageId = dockerClient.buildImageCmd()
  .withDockerfile(new File("path/to/Dockerfile"))
  .withPull(true)
  .withNoCache(true)
  .withTag("alpine:git")
  .exec(new BuildImageResultCallback())
  .awaitImageId();

5.3. Inspect an Image

We can inspect the low-level information about an image thanks to the inspectImageCmd method:

InspectImageResponse image
  = dockerClient.inspectImageCmd("161714540c41").exec();

5.4. Tag an Image

Adding a tag to our image is quite simple using the docker tag command, so the API is no exception. We can carry out the same intention with the tagImageCmd method as well. To tag a Docker image with id 161714540c41 into the baeldung/alpine repository with git:

String imageId = "161714540c41";
String repository = "baeldung/alpine";
String tag = "git";

dockerClient.tagImageCmd(imageId, repository, tag).exec();

We would list the newly created image, and there it is:

$ docker image ls --format "table {{.Repository}} {{.Tag}}"
REPOSITORY      TAG
baeldung/alpine git

5.5. Push an Image

Before sending out an image to a registry service, the docker client must be configured to cooperate with the service because working with registries need to be authenticated in advance.

Since we assume that the client was configured with Docker Hub, we can push the baeldung/alpine image to the baeldung DockerHub account:

dockerClient.pushImageCmd("baeldung/alpine")
  .withTag("git")
  .exec(new PushImageResultCallback())
  .awaitCompletion(90, TimeUnit.SECONDS);

We must abide by the duration of the process. In the example, we are waiting 90 seconds.

5.6. Pull an Image

To download images from registry services, we make use of the pullImageCmd method. In addition, if the image being pulled from a private registry, the client must know our credential otherwise the process ends up with a failure. Same as the pulling an image, we specify a callback along with a fixed period to pull an image:

dockerClient.pullImageCmd("baeldung/alpine")
  .withTag("git")
  .exec(new PullImageResultCallback())
  .awaitCompletion(30, TimeUnit.SECONDS);

To check out whether the mentioned image exists on the Docker host after pulling it:

$ docker images baeldung/alpine --format "table {{.Repository}} {{.Tag}}"
REPOSITORY      TAG
baeldung/alpine git

5.7. Remove an Image

Another simple function among the rest is the removeImageCmd method. We can remove an image with its short or long ID:

dockerClient.removeImageCmd("beaccc8687ae").exec();

5.8. Search in Registry

To search an image from Docker Hub, the client comes with the searchImagesCmd method taking a String value which indicates a term. Here, we explore images related to a name containing ' Java' in Docker Hub:

List<SearchItem> items = dockerClient.searchImagesCmd("Java").exec();

The output returns first 25 related images in a list of SearchItem objects.

6. Volume Management

If Java projects need to interact with Docker for volumes, we should also take into account this section. Briefly, we look at the fundamental techniques of volumes provided by the Docker Java API.

6.1. List Volumes

All of the available volumes including named and unnamed are listed with:

ListVolumesResponse volumesResponse = dockerClient.listVolumesCmd().exec();
List<InspectVolumeResponse> volumes = volumesResponse.getVolumes();

6.2. Inspect a Volume

The inspectVolumeCmd method is the form to show the detailed information of a volume. We inspect the volume by specifying its short id:

InspectVolumeResponse volume
  = dockerClient.inspectVolumeCmd("0220b87330af5").exec();

6.3. Create a Volume

The API serves two different options to create a volume. The non-arg createVolumeCmd method creates a volume where the name is given by Docker:

CreateVolumeResponse unnamedVolume = dockerClient.createVolumeCmd().exec();

Rather than using the default behavior, the helper method called withName lets us set a name to a volume:

CreateVolumeResponse namedVolume
  = dockerClient.createVolumeCmd().withName("myNamedVolume").exec();

6.4. Remove a Volume

We can intuitively delete a volume from the Docker host using the removeVolumeCmd method. What is important to note that we cannot delete a volume if it is in use from a container. We remove the volume, myNamedVolume, from the volume list:

dockerClient.removeVolumeCmd("myNamedVolume").exec();

7. Network Management

Our last section is about managing network tasks with the API.

7.1. List Networks

We can display the list of network units with one of the conventional API methods starting with list:

List<Network> networks = dockerClient.listNetworksCmd().exec();

7.2. Create a Network

The equivalent of the docker network create command is conducted with the createNetworkCmd method. If we have a thirty party or a custom network driver, the withDriver method can accept them besides the built-in drivers. In our case, let's create a bridge network whose name is baeldung:

CreateNetworkResponse networkResponse
  = dockerClient.createNetworkCmd()
    .withName("baeldung")
    .withDriver("bridge").exec();

Furthermore, creating a network unit with the default settings doesn't solve the problem, we can apply for other helper methods to construct an advanced network. Thus, to override the default subnetwork with a custom value:

CreateNetworkResponse networkResponse = dockerClient.createNetworkCmd()
  .withName("baeldung")
  .withIpam(new Ipam()
    .withConfig(new Config()
    .withSubnet("172.36.0.0/16")
    .withIpRange("172.36.5.0/24")))
  .withDriver("bridge").exec();

The same command we can run with the docker command is:

$ docker network create \
  --subnet=172.36.0.0/16 \
  --ip-range=172.36.5.0/24 \
  baeldung

7.3. Inspect a Network

Displaying the low-level details of a network is also covered in the API:

Network network
  = dockerClient.inspectNetworkCmd().withNetworkId("baeldung").exec();

7.4. Remove a Network

We can safely remove a network unit with its name or id using the removeNetworkCmd method:

dockerClient.removeNetworkCmd("baeldung").exec();

8. Conclusion

In this extensive tutorial, we explored the various diverse functionality of the Java Docker API Client, along with several implementation approaches for deployment and management scenarios.

All the examples illustrated in this article can be found over on GitHub.

# data[].attributes.attachment_link.description
In this article, we take a look at another well-established platform specific API - Java API Client for Docker . Throughout the article, we comprehend the way of how to connect with a running Docker daemon and what type of important functionality the API offers to Java developers.

# data[].attributes.body
Nathan, Brady, Ali and Ruben in attendance.

The team will continue with Docker and Docker Swarm tutorials on their Pi. The leads for the Portal App, Java API, and Cluster were assigned out. Brady and Tyler are still cross training.

# data[].attributes.body
Brady and Ruben in attendance.

1. All team members must be able to build and run one or more Docker images.
2. All team members must be able to build and run one of the custom Docker Images.
3. Brady met with Tyler and has everything he needs.
4. Ruben: Run Portal App
Nathan and Ali: Run API
Brady: Get POC Running
Brady: Get HSET Poster
Mark: Get POC Moved to Lab
5. Received 10 Sense HATS.

# data[].attributes.attachment_link.readable_text
Navigate to /lib/system/system in your terminal and open docker.service file:
 	vi /lib/systemd/system/docker.service
 
Find the line which starts with ExecStart and adds  -H=tcp://0.0.0.0:2375 to modify it as follows:
	ExecStart=/usr/bin/docker daemon -H=fd:// -H=tcp://0.0.0.0:2375
 
Save the Modified File and reload the docker daemon:
	systemctl daemon-reload
 
Restart the docker service:
	sudo service docker restart

# data[].attributes.body
Nathan in attendance. Brady indicated he could not attend.

Nathan is looking over the GCU Java API but still needs to validate that his Pi works with the API.

Brady is still validating the 4 node cluster in preparation for HSET. Brady finished the HSET posters. Mark is getting these printed this week.

# data[].attributes.body
Brady in attendance.Ruben contacted me thru Remind.

The cluster is broken and all the Pis' need to be re-imaged in preparation for HSET. HSET posters were printed. Ruben has the Portal App built and is ready to add new functionality.

# data[].attributes.body
Brady and Nathan in attendance.

Planning out the rest of the semester to find a stopping point for the 4 node cluster. Had discussions on network design. Brady might have time this week to get the 20 node cluster configured and operational.

.

# data[].attributes.body
Reuben, Kevin, and Matthew in attendance. Will meet with Brandy this coming Monday.

2 new members joined the team. No progress on storage strategy. Reuben to take over task. Detached issue still open. Reuben to work with Brady on other solutions.

# data[].attributes.body
Reuben in attendance.

Brady is working on reverse proxy setup for the networking solution. Not sure why detached issue is a problem as Brady or myself have not observed this issue.

Reuben going to figure why he has an issue with detached mode for Nginx. Reuben is going to get the initial storage hooks put in the API for next week. Matt and Kevin both have their Pi's running and using VNC, they will both move onto Docker tutorials. Matt to hook up with Brady.

# data[].attributes.body
Reuben and Kevin in attendance.

Reuben fixing a build issue with the Java API and will write a proposal for the storage solution.

Brady should get networking started this week.

# data[].attributes.body
Reuben and Kevin in attendance.

After inquiring with Nathan why he was making no progress, he said he  decided to drop out of the RDP (despite communicating this to the team at the start of the semester).

Brady determined that the Reverse Proxy for Docker that he found is not available for use on the Pi architecture. We discussed using the same IP based network architecture used today and explore Kubernetes as an RDP project for Fall of 2020.

Brady validated that the Java API still works on the cluster. Reuben did get this working.

Goal is to finish the storage strategy next week and with the NAS drive.