<<TableOfContents(2)>>

= Docker =
Docker is an open platform for developers and sysadmins to build, ship, and run distributed applications.

http://www.zdnet.com/article/what-is-docker-and-why-is-it-so-darn-popular/

Developers can use Docker to pack, ship, and run any application as a lightweight, portable, self sufficient LXC container that can run virtually anywhere. 

In a nutshell, here's what Docker can do for you: It can get more applications running on the same hardware than other technologies; it makes it easy for developers to quickly create, ready-to-run containered applications; and it makes managing and deploying applications much easier.

http://en.wikipedia.org/wiki/LXC

LXC (Linux Containers) is an operating system–level virtualization method for running multiple isolated Linux systems (containers) on a single control host.

LXC provides operating system-level virtualization through a virtual environment that has its own process and network space, instead of creating a full-fledged virtual machine.

== Tutorial ==
https://www.docker.com/tryit

https://hub.docker.com/

https://docs.docker.com/installation

https://docs.docker.com/articles/basics/

== Windows install ==
https://docs.docker.com/installation/windows/

The Docker Engine uses Linux-specific kernel features, so to run it on Windows we need to use a lightweight virtual machine (vm).

== Hello world ==
{{{#!highlight sh
docker run hello-world
}}}

== Docker SSH container Ubuntu ==
https://docs.docker.com/examples/running_ssh_service/

In bootDocker create ~/ssh/Dockerfile :
{{{#!highlight sh
# sshd
#
# VERSION               0.0.2

FROM ubuntu:14.04
MAINTAINER Sven Dowideit <SvenDowideit@docker.com>

RUN apt-get update && apt-get install -y openssh-server
RUN mkdir /var/run/sshd
RUN echo 'root:screencast' | chpasswd
RUN sed -i 's/PermitRootLogin without-password/PermitRootLogin yes/' /etc/ssh/sshd_config

# SSH login fix. Otherwise user is kicked off after login
RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd

ENV NOTVISIBLE "in users profile"
RUN echo "export VISIBLE=now" >> /etc/profile

EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]
}}}

{{{#!highlight sh
docker build -t eg_sshd .
docker run -d -P --name test_sshd eg_sshd
docker ps -l
ssh root@127.0.0.1 -p49153 # password screencast
sudo docker stop test_sshd # stop container test_sshd
}}}

== Install jdk8 in trusty ==
{{{#!highlight sh
apt-get install software-properties-common
add-apt-repository ppa:openjdk-r/ppa -y
apt-get update
apt-get install openjdk-8-jdk
}}}

Dockerfile
{{{#!highlight sh
FROM ubuntu:14.04

RUN apt-get update && \
    apt-get install -y traceroute openssh-server software-properties-common mongodb rabbitmq-server  && \
    add-apt-repository ppa:openjdk-r/ppa -y && \
    apt-get update && \
    apt-get install -y openjdk-8-jdk

RUN mkdir /var/run/sshd
RUN echo 'root:12345678' | chpasswd
RUN sed -i 's/PermitRootLogin without-password/PermitRootLogin yes/' /etc/ssh/sshd_config

# SSH login fix. Otherwise user is kicked off after login
RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd

ENV NOTVISIBLE "in users profile"
RUN echo "export VISIBLE=now" >> /etc/profile

EXPOSE 22 8080 8081 8082 5672 15672 27017 80
CMD ["/usr/sbin/sshd", "-D"]
}}}

== Install Docker CE slack 64 14.2 ==
 * https://slackbuilds.org/repository/14.2/system/docker/

=== Install go lang ===
{{{#!highlight sh
cd /tmp
wget https://slackbuilds.org/slackbuilds/14.2/development/google-go-lang.tar.gz
tar xvzf google-go-lang.tar.gz
cd google-go-lang
wget https://storage.googleapis.com/golang/go1.10.1.src.tar.gz
# change slackbuild to use 1.10.1
./google-go-lang.SlackBuild
# installpkg /tmp/google-go-lang-1.9.5-x86_64-1_SBo.tgz
go --version 

# In ~/.bashrc 
export GOPATH="$HOME:/usr/share/gocode"
go help buildmode
go get golang.org/x/tools/cmd/godoc

# remove support to gcc-go !

/usr/lib64/go1.10.1/go/bin/
/usr/lib64/go1.10.1/go/bin/go version
# in ~/.bashrc
export PATH="$PATH:/usr/lib64/go1.10.1/go/bin/"
}}}

=== Install docker-proxy ===
{{{#!highlight sh
cd /tmp
wget https://slackbuilds.org/slackbuilds/14.2/system/docker-proxy.tar.gz
tar xvzf docker-proxy.tar.gz
cd docker-proxy
wget https://github.com/docker/libnetwork/archive/1b91bc9/libnetwork-1b91bc94094ecfdae41daa465cc0c8df37dfb3dd.tar.gz
./docker-proxy.SlackBuild 
installpkg /tmp/docker-proxy-20180314_1b91bc9-x86_64-1_SBo.tgz
}}}

=== Install tini ===
{{{#!highlight sh
cd /tmp
wget https://slackbuilds.org/slackbuilds/14.2/system/tini.tar.gz
tar xvzf tini.tar.gz 
cd tini
wget https://github.com/krallin/tini/archive/949e6fa/tini-949e6facb77383876aeff8a6944dde66b3089574.tar.gz
./tini.SlackBuild 
installpkg /tmp/tini-0.13.0_949e6fa-x86_64-1_SBo.tgz 
}}}

=== Install libseccomp ===
{{{#!highlight sh
cd /tmp
wget https://slackbuilds.org/slackbuilds/14.2/libraries/libseccomp.tar.gz
tar xvzf libseccomp.tar.gz
cd libseccomp
wget https://github.com/seccomp/libseccomp/archive/v2.3.3/libseccomp-2.3.3.tar.gz
./libseccomp.SlackBuild 
installpkg /tmp/libseccomp-2.3.3-x86_64-1_SBo.tgz 
}}}

=== Install runc ===
{{{#!highlight sh
cd /tmp
wget https://slackbuilds.org/slackbuilds/14.2/system/runc.tar.gz
tar xvzf runc.tar.gz 
cd runc
wget https://github.com/opencontainers/runc/archive/v1.0.0-rc5/runc-1.0.0-rc5.tar.gz
./runc.SlackBuild 
installpkg /tmp/runc-1.0.0_rc5-x86_64-1_SBo.tgz
}}}

=== Install containerd ===
{{{#!highlight sh
cd /tmp
wget https://slackbuilds.org/slackbuilds/14.2/system/containerd.tar.gz
tar xvzf containerd.tar.gz
cd containerd
wget https://github.com/containerd/containerd/archive/v1.0.2/containerd-1.0.2.tar.gz
./containerd.SlackBuild 
installpkg /tmp/containerd-1.0.2-x86_64-1_SBo.tgz
}}}

=== Install docker ===
{{{#!highlight sh
cd /tmp
wget https://slackbuilds.org/slackbuilds/14.2/system/docker.tar.gz
tar xvzf docker.tar.gz
cd docker 
wget https://github.com/docker/docker-ce/archive/v18.03.0-ce/docker-ce-18.03.0-ce.tar.gz
./docker.SlackBuild
installpkg /tmp/docker-18.03.0-x86_64-1_SBo.tgz

# Added option --userland-proxy=false in  /etc/rc.d/rc.docker variable 
DOCKER_OPTS="--userland-proxy=false"

cd /etc/rc.d
sh rc.docker status
sh rc.docker start
}}}

== Docker image with SSH Ubuntu Xenial 16.04 ==
Adapted from https://docs.docker.com/engine/examples/running_ssh_service/

Dockerfile:
{{{#!highlight sh
# https://docs.docker.com/engine/examples/running_ssh_service/
FROM ubuntu:16.04

RUN apt-get update && apt-get install -y openssh-server
RUN mkdir /var/run/sshd
RUN echo 'root:screencast' | chpasswd
RUN sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config

# SSH login fix. Otherwise user is kicked off after login
RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd

ENV NOTVISIBLE "in users profile"
RUN echo "export VISIBLE=now" >> /etc/profile
RUN useradd userx
RUN echo 'userx:userx' | chpasswd

EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]
}}}

Steps:
{{{#!highlight sh
docker build -t docker_test . 
docker run -d -P --name test_container1 docker_test 
docker ps -a
ssh root@127.0.0.1 -p32771
useradd userx
echo 'userx:userx' | chpasswd
ssh userx@127.0.0.1 -p32771
docker exec -it test_container1 /bin/bash
docker container stop test_container1
docker container rm test_container1
docker image rm docker_test
}}}

== Install Docker in Ubuntu Xenial (16.04.4) vagrant box ==
{{{#!highlight sh
mkdir tmp
cd tmp
vagrant init ubuntu/xenial64
vagrant up
vagrant ssh
# inside the box with user vagrant
sudo bash
apt-get update
apt-get install apt-transport-https  ca-certificates curl  software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
apt-key fingerprint 0EBFCD88
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
apt-get update
apt-get install docker-ce
docker run hello-world
usermod -aG docker
exit
exit
#login again with vagrant ssh
# as user vagrant 
docker run hello-world
# install java and maven 
apt-get install openjdk-8-jdk
apt-get install maven
}}}

== Commands ==
{{{#!highlight sh
docker ps -a # showall containers
# clean system including volumes without asking for permission
docker system prune -a -f --volumes 
docker ps -a | awk '//{print $1}' | grep  -v "CONTAINER" | xargs -i sh -c 'docker stop {};docker rm {}'  # clear all containers
docker build -t acme_app . # build image from docker file
docker run -P -p 8080:80 -d acme_app # run dettached container from image acme_app mapping port 8080 to port exposed 80
}}}

== Docker DNS server ==
 * https://docs.docker.com/v17.09/engine/userguide/networking/configure-dns/
{{{
As of Docker 1.10, the docker daemon implements an embedded DNS server which provides built-in service discovery for any container created with a valid name or net-alias or aliased by link.

So you should not assume the way the files such as /etc/hosts, /etc/resolv.conf are managed inside the containers and leave the files alone and use the following Docker options instead.

Note: The DNS server is always at 127.0.0.11.
}}}

== Docker container based on GCC image ==
{{{#!highlight sh
docker run -it gcc /bin/bash
docer ps -a
docker exec -it <container> /bin/bash
# inside container
cat /etc/os-release
apt-get update
}}}

== Docker playground - cherrypy ==
 * https://www.katacoda.com/courses/docker/playground
=== Dockerfile ===
{{{#!highlight sh
# docker build -t image_cherrypy . # build image from Dockerfile
# docker run -P -p 8080:80 -d image_cherrypy
# touch cherrypytest.wsgi
# links http://localhost/add/3/4
# curl -X POST -d "{\"name\":\"jkl\"}" http://localhost/hellojson --header "Content-Type:application/json"
# curl -X POST -d "{\"name\":\"jkl\"}" http://localhost:1234/hellojson --header "Content-Type:application/json"
FROM ubuntu:16.04
RUN apt-get update && apt-get install -y python libapache2-mod-wsgi apache2 vim links net-tools nano curl wget
RUN wget https://pypi.python.org/packages/source/C/CherryPy/CherryPy-3.2.4.tar.gz
RUN cp CherryPy-3.2.4.tar.gz /tmp
RUN cd /tmp && tar xvzf CherryPy-3.2.4.tar.gz
RUN cd /tmp/CherryPy-3.2.4 && python setup.py build && python setup.py install
RUN mkdir -p /var/www/htdocs/cherrypytest/static
# copy cherrypytest.wsgi from where the Dockerfile is
COPY cherrypytest.wsgi /var/www/htdocs/cherrypytest/cherrypytest.wsgi
RUN echo "Static Test" > /var/www/htdocs/cherrypytest/static/a.txt
RUN echo "<VirtualHost *:80>\nServerName localhost\nDocumentRoot \"/var/www/htdocs/cherrypytest\"\nWSGIScriptAlias / /var/www/htdocs/cherrypytest/cherrypytest.wsgi\n<Directory \"/var/www/htdocs/cherrypytest\">\nRequire all granted\n</Directory>\n</VirtualHost>" > /etc/apache2/sites-available/000-default.conf
RUN echo "#!/bin/sh\n service apache2 start \n tail -f /var/log/apache2/error.log" > /start.sh
EXPOSE 80
CMD ["sh","/start.sh"]
}}}

=== cherrypytest.wsgi ===
{{{#!highlight python
import sys
sys.stdout = sys.stderr
import cherrypy

cherrypy.config.update({'environment': 'embedded'})

class HelloWorld(object):
    @cherrypy.expose
    def index(self):
        return "Hello World CherryPy!!!!"

    @cherrypy.expose
    def add(self,param1,param2):
       # curl "http://localhost:1234/add/2/100"
       # curl "http://localhost:1234/add?param1=2&param2=100"
       print "Called add"
       return str( int(param1)+int(param2) )

    @cherrypy.expose
    @cherrypy.tools.json_in()
    @cherrypy.tools.json_out()
    def hellojson(self): 
        # curl -X POST -d "{\"name\":\"jkl\"}" http://localhostcherrypytest/hellojson --header "Content-Type:application/json"
        # curl -X POST -d "{\"name\":\"jkl\"}" http://localhost:1234/hellojson --header "Content-Type:application/json"
        inj = cherrypy.request.json
        return {"message": "hello world " + inj['name'] }

hello = HelloWorld()    
#static dir
confx={'/static': {'tools.staticdir.on':True ,
                  'tools.staticdir.dir':'/var/www/htdocs/cherrypytest/static'
                  }}
application = cherrypy.Application(hello, script_name=None, config=confx)
}}}

=== Execute ===
{{{#!highlight sh
docker build -t docker-cherrypy-image .
docker run -it -P --rm --name docker-cherrypy-container docker-cherrypy-image 
docker ps
docker exec -it docker-cherrypy-container bash
# in container
curl -vv localhost

docker run -it -p 1234:80 --rm --name docker-cherrypy-container docker-cherrypy-image
curl -vv localhost:1234
}}}

== Docker - openjdk8 - hello ==

=== Main.java ===
{{{#!highlight java
//Main.java
public class Main{
    public static void main(String args[]){
        System.out.println("Hello docker!");
    }
}
}}}

=== Dockerfile ===
{{{#!highlight sh
FROM openjdk:8-alpine
RUN mkdir -p /usr/src/hello_docker
COPY . /usr/src/hello_docker
WORKDIR /usr/src/hello_docker
RUN javac Main.java
CMD ["java", "Main"]
}}}

=== Execute ===
{{{#!highlight sh
# build image hello-docker-image using Dockerfile
docker build -t hello-docker-image . 
# run the container based on the image
docker run -it --rm --name hello-docker hello-docker-image 
}}}

== Docker - openjdk 8 - hello - maven ==
 * mkdir -p src/main/java/com/example/artifactX

=== pom.xml ===
{{{#!highlight xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
        http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>artifactX</artifactId>
  <packaging>jar</packaging>
  <version>0.0.1</version>
  <name>artifactX</name>
  <url>http://maven.apache.org</url>
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>2.4</version>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
          <archive>
            <manifest>
              <mainClass>com.example.artifactX.Main</mainClass>
            </manifest>
          </archive>
        </configuration>
        <executions>
          <execution>
            <id>make-assembly</id> 
            <phase>package</phase> 
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  <dependencies>
  </dependencies>
</project>
}}}

=== src/main/java/com/example/artifactX/Main.java ===
{{{#!highlight java
package com.example.artifactX;
//Main.java
public class Main{
    public static void main(String args[]){
        System.out.println("Hello docker!");
    }
}
}}}

=== Dockerfile ===
{{{#!highlight sh
FROM openjdk:8-alpine
RUN apk add maven
RUN mkdir -p /usr/src/hello_maven_docker 
COPY . /usr/src/hello_maven_docker 
WORKDIR /usr/src/hello_maven_docker 
RUN mvn clean install
CMD ["java", "-jar" , "target/artifactX-0.0.1-jar-with-dependencies.jar"]
}}}

=== Execute ===
{{{#!highlight sh
docker build -t hello-maven-docker-image .
docker run -it --rm --name hello-maven-docker hello-maven-docker-image
}}}

== docker - maven - springboot-test ==
{{{#!highlight sh
touch Dockerfile
touch pom.xml
mkdir -p src/main/java/hello/
mkdir -p src/main/resources/templates/
touch src/main/java/hello/GreetingController.java
touch src/main/java/hello/Application.java
touch src/main/java/hello/ThreadTimer.java
touch src/main/java/hello/WaitThread.java
touch src/main/java/hello/Dummy.java
touch src/main/resources/templates/greeting.html
touch src/main/resources/application.properties
touch src/main/resources/logback-spring.xml
mvn clean install
java -Dfilelog=/tmp/out.log -jar target/test-spring-boot-0.1.0.jar
# http://localhost:8080/greeting
}}}

=== Dockerfile ===
{{{#!highlight sh
FROM openjdk:8-alpine
RUN apk add maven
RUN mkdir -p /usr/src/hello_springboot_docker 
COPY . /usr/src/hello_springboot_docker 
WORKDIR /usr/src/hello_springboot_docker 
RUN mvn clean install
CMD ["java","-Dfilelog=/tmp/out.log","-jar","target/test-spring-boot-0.1.0.jar"]
}}}

=== pom.xml ===
{{{#!highlight xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>hello</groupId>
    <artifactId>test-spring-boot</artifactId>
    <version>0.1.0</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.4.0.RELEASE</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
    </dependencies>
    <properties>
        <start-class>hello.Application</start-class>
    </properties>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
    <repositories>
        <repository>
            <id>spring-milestone</id>
            <url>http://repo.spring.io/libs-release</url>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>spring-milestone</id>
            <url>http://repo.spring.io/libs-release</url>
        </pluginRepository>
    </pluginRepositories>
</project>
}}}

=== src/main/java/hello/GreetingController.java ===
{{{#!highlight java
package hello;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
import java.util.ArrayList;

@Controller
public class GreetingController {
    private final Logger logger = LoggerFactory.getLogger(GreetingController.class);

    public GreetingController(){
        logger.debug("Greeting controller created.");
    }

    @RequestMapping("/greeting")
    // http://localhost:8080/greeting?name=nnnn 
    public String greeting(@RequestParam(value="name", required=false, defaultValue="World") String name, Model model) {
        logger.info("Greeting endpoint called.");
        model.addAttribute("name", name);
        return "greeting";
    }

    @RequestMapping(value="/dummy",produces="application/json")
    @ResponseBody
    // http://localhost:8080/dummy
    public List<Dummy> dummy(){
      List<Dummy> list= new java.util.ArrayList<Dummy>();
      Dummy dummy = new Dummy();
      dummy.setFieldA("AAA");
      dummy.setFieldB("CCC");
      list.add(dummy);

      Dummy dummy2 = new Dummy();
      dummy2.setFieldA("AAA2");
      dummy2.setFieldB("CCC2");
      list.add(dummy2);

      return list;
    }

}
}}}

=== src/main/java/hello/Application.java ===
{{{#!highlight java
package hello;

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Bean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@ComponentScan
@EnableAutoConfiguration
public class Application {
    private static Logger logger;

    public static void main(String[] args) {
        logger = LoggerFactory.getLogger(Application.class);
        logger.info("Starting application");
        SpringApplication.run(Application.class, args);
    }

}
}}}

=== src/main/java/hello/ThreadTimer.java ===
{{{#!highlight java
package hello;

import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import java.text.MessageFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;

@Component
public class ThreadTimer extends Thread {
  private int delaySeconds;
  private Logger logger;
  private boolean running;
  private Object monitor=new Object();
  private ArrayList<Object> subscribers;

  //@Autowired
  //WaitThread waitThread;

  public ThreadTimer() {
    this.logger = LoggerFactory.getLogger(ThreadTimer.class);
    logger.info("Created instance of " + this.getClass().getSimpleName());
    this.running = true;
    this.delaySeconds = 5 * 1000;
    this.setName(this.getClass().getSimpleName() + "_" + this.getName());
    this.subscribers = new ArrayList<Object>();
  }

  public void addSubscriber(Object subscriber){
    this.subscribers.add(subscriber);
  }

  @PostConstruct
  public void init() {
    logger.info("Starting the thread");
    this.start();
  }

  @Override
  public void run() {
    while (running) {
      try {
        Thread.sleep(this.delaySeconds);
        logger.info("Delay " + this.getClass().getSimpleName());

        for(Object o: this.subscribers){
          synchronized(o){
            o.notify();
          }
        }
      }
      catch (InterruptedException e) {
          logger.info("ThreadTimer interrupted exception:" + e.getMessage() );
      }
      catch (Exception e) {
          e.printStackTrace();
          logger.info("ThreadTimer exception:" + e.getMessage() );
          stopRunning();
      }
    }
    logger.info("Exited " + this.getClass().getSimpleName());
  }

  public void startRunning() {
    this.running = true;
  }

  public void stopRunning() {
    this.running = false;
  }

  public void destroy(){
    logger.info("Called destroy");
    this.stopRunning();
    this.interrupt();
  }
}
}}}

=== src/main/java/hello/WaitThread.java ===
{{{#!highlight java
package hello;

import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.text.MessageFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

@Component
public class WaitThread extends Thread {
  private Logger logger;
  private boolean running;
  private Object monitor;

  @Autowired
  ThreadTimer timerThread;

  public WaitThread() {
    this.logger = LoggerFactory.getLogger(WaitThread.class);
    logger.info("Created instance of " + this.getClass().getSimpleName());
    this.running = true;
    this.setName(this.getClass().getSimpleName() + "_" + this.getName());
    this.monitor=new Object();
  }

  @PostConstruct
  public void init() {
    this.timerThread.addSubscriber(this);
    logger.info("Starting the thread");
    this.start();
  }

  public void run() {
    while (running) {
      try {
        synchronized(this){
          this.wait();
          logger.info("Notification received.");
        }
      }
      catch (InterruptedException e) {
          logger.info("ThreadTimer interrupted exception:" + e.getMessage() );
      }
      catch (Exception e) {
          logger.info("WaitThread exception:" + e.getMessage() );
          stopRunning();
      }
    }
    logger.info("Exited " + this.getClass().getSimpleName());
  }

  public void startRunning() {
    this.running = true;
  }

  public void stopRunning() {
    this.running = false;
  }

  public void destroy(){
    logger.info("Called destroy");
    this.stopRunning();
    this.interrupt();
  }
}
}}}

=== src/main/java/hello/Dummy.java ===
{{{#!highlight java
package hello;

public class Dummy{
  private String fieldA;
  private String fieldB;

  public Dummy(){
  }

  public String getFieldA(){
    return fieldA;
  }

  public String getFieldB(){
    return fieldB;
  }

  public void setFieldA(String arg){
    fieldA = arg;
  }

  public void setFieldB(String arg){
    fieldB = arg;
  }
}
}}}

=== src/main/resources/templates/greeting.html ===
{{{#!highlight xml
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Getting Started: Serving Web Content</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
    <p th:text="'Hello, ' + ${name} + '!'" />
</body>
</html>
}}}

=== src/main/resources/application.properties ===
{{{#!highlight sh
logging.file=/tmp/testout.log
}}}

=== src/main/resources/logback-spring.xml ===
{{{#!highlight xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!--
    <include resource="org/springframework/boot/logging/logback/defaults.xml" />
    <property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}spring.log}"/>
    <include resource="org/springframework/boot/logging/logback/file-appender.xml" />
-->
    <!-- override spring logback default behaviour -->
    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>${filelog}</file>
        <encoder>
                <pattern>%date{ISO8601} [%thread] %-5level %logger{35} - %msg%n</pattern>
        </encoder>
    </appender>
    <appender name="GREETFILE" class="ch.qos.logback.core.FileAppender">
        <file>/tmp/greet.log</file>
        <encoder>
                <pattern>%date{ISO8601} [%thread] %-5level %logger{35} - %msg%n</pattern>
        </encoder>
    </appender>
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
                <Pattern>%yellow(%date{ISO8601}) %green([%thread]) %highlight(%-5level) %cyan(%logger{35}) - %white(%msg%n) </Pattern>
        </layout>
    </appender>
    <root level="INFO">
        <appender-ref ref="FILE" />
        <appender-ref ref="CONSOLE"/>
    </root>
    <logger name="hello.GreetingController" level="debug" additivity="false">
        <appender-ref ref="GREETFILE"/>
        <appender-ref ref="CONSOLE" />
    </logger>
</configuration>
}}}

=== Execute ===
 * docker build -t hello-springboot-docker-image .
 * docker run -P -p 8080:8080 --name hello-springboot-docker -d hello-springboot-docker-image
 * docker ps
 * docker exec -it 5ea9eaff4616 /bin/ash
 * docker exec -it 5ea9eaff4616 /bin/sh
 * curl http://localhost:8080/greeting
 * curl http://localhost:8080/greeting?name=asdf
 * curl http://localhost:8080/dummy

== Docker registry ==
 * https://hub.docker.com/_/registry
{{{#!highlight bash
# local registry
CONTAINER_NAME=registry
IMAGE_NAME=registry:2
docker run -d -p 5000:5000 --restart always --name $CONTAINER_NAME $IMAGE_NAME
}}}

 * Check images catalog in registry
  * http://hostx:5000/v2/_catalog
  * http://hostx:5000/v2/image/tags/list 

== Bind mount ==
 * https://docs.docker.com/storage/bind-mounts/
When you use a bind mount, a file or directory on the host machine is mounted into a container.

{{{#!highlight sh
docker run -d \
  -it \
  --name devtest \
  --mount type=bind,source="$(pwd)"/target,target=/app \
  nginx:latest
}}}

== Install docker in nb200 (32 bit) ==
{{{#!highlight sh
# install go
cd /tmp
wget https://slackbuilds.org/slackbuilds/14.2/development/google-go-lang.tar.gz
tar xvzf google-go-lang.tar.gz
cd google-go-lang
wget https://storage.googleapis.com/golang/go1.11.13.src.tar.gz
nano google-go-lang.SlackBuild 
./google-go-lang.SlackBuild
installpkg /tmp/google-go-lang-1.11.13-i586-1_SBo.tgz 
go --version
nano ~/.bashrc
go --version
source . 
source ~/.bashrc
go --version
/usr/lib/go1.11.13/go/bin/go --version
/usr/lib/go1.11.13/go/bin/go version
go version
nano ~/.bashrc
source ~/.bashrc
go version
echo $PATH
nano ~/.bashrc
exit
go version
which go
go help buildmode
echo $PATH
cat /root/.bashrc
export PATH="$PATH:/usr/lib64/go1.11.13/go/bin/"
go help buildmode
go version
echo $PATH
go version
removepkg gcc-go-5.5.0-i586-1_slack14.2
go version
echo $PATH
nano ~/.bashrc
source ~/.bashrc
go version
cat ~/.bashrc
# install docker proxy
cd /tmp
wget https://slackbuilds.org/slackbuilds/14.2/system/docker-proxy.tar.gz
tar xvzf docker-proxy.tar.gz
cd docker-proxy
wget https://github.com/docker/libnetwork/archive/2cfbf9b/libnetwork-2cfbf9b1f98162a55829a21cc603c76072a75382.tar.gz
./docker-proxy.SlackBuild 
installpkg/tmp/docker-proxy-20181207_2cfbf9b-i586-1_SBo.tgz
# install tini
cd /tmp
wget https://slackbuilds.org/slackbuilds/14.2/system/tini.tar.gz
tar xvzf tini.tar.gz 
cd tini
wget https://github.com/krallin/tini/archive/v0.18.0/tini-0.18.0.tar.gz
./tini.SlackBuild 
installpkg/tmp/tini-0.18.0-i586-1_SBo.tgz
# install libseccomp
cd /tmp
wget https://slackbuilds.org/slackbuilds/14.2/libraries/libseccomp.tar.gz
tar xvzf libseccomp.tar.gz
cd libseccomp
wget https://github.com/seccomp/libseccomp/archive/v2.4.2/libseccomp-2.4.2.tar.gz
./libseccomp.SlackBuild 
installpkg/tmp/libseccomp-2.4.2-i586-1_SBo.tgz
# install runc
cd /tmp
wget https://slackbuilds.org/slackbuilds/14.2/system/runc.tar.gz
tar xvzf runc.tar.gz 
cd runc
wget https://github.com/opencontainers/runc/archive/8084f76/runc-8084f7611e4677174c8dbeb17152f3390fa41952.tar.gz
./runc.SlackBuild
installpkg /tmp/runc-1.0.0_rc6_8084f76-i586-1_SBo.tgz
# install containerd
cd /tmp
wget https://slackbuilds.org/slackbuilds/14.2/system/containerd.tar.gz
tar xvzf containerd.tar.gz
cd containerd
wget https://github.com/containerd/containerd/archive/v1.2.4/containerd-1.2.4.tar.gz
./containerd.SlackBuild 
installpkg/tmp/containerd-1.2.4-i586-1_SBo.tgz
# install docker
cd /tmp
wget https://slackbuilds.org/slackbuilds/14.2/system/docker.tar.gz
tar xvzf docker.tar.gz
cd docker 
wget https://github.com/docker/docker-ce/archive/v18.09.2/docker-ce-18.09.2.tar.gz
vi docker.SlackBuild 
# change to docker-linux-386
./docker.SlackBuild
installpkg /tmp/docker-18.09.2-i586-1_SBo.tgz
cd /etc/rc.d
sh rc.docker status
sh rc.docker start
groupadd -r -g 281 docker
usermod -a -G docker vitor
}}}

== Docker + cherrypy ==
=== Setup environment ===
{{{#!highlight python
cd ~
mkdir env-docker-cherry
cd env-docker-cherry
touch Dockerfile
mkdir target
touch target/cherry.py
}}}

=== Ubuntu Dockerfile ===
{{{#!highlight sh
FROM ubuntu:20.04
RUN apt update
RUN apt-get install -y curl sudo wget python net-tools vim
RUN mkdir /app
RUN cd /app && curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
RUN cd app/ && python get-pip.py && pip install cherrypy
RUN echo "#!/bin/sh\n python /app/cherry.py" > /start.sh
EXPOSE 80 22 8080 8081
CMD ["sh","/start.sh"]
}}}

=== Alpine Dockerfile ===
{{{#!highlight sh
touch Dockerfile
mkdir target
touch target/cherry.py
}}}

{{{#!highlight sh
FROM alpine:3.16 
RUN apk add --update --no-cache python3 curl wget 
RUN mkdir /app
RUN cd /app && curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
RUN cd app/ && python3 get-pip.py && pip install cherrypy
EXPOSE 80 22 8080 8081
CMD ["python3","/app/cherry.py"]
}}}

=== target/cherry.py ===
{{{#!highlight python
import cherrypy
import json

cherrypy.config.update({'server.socket_port': 8081})
cherrypy.config.update({'server.socket_host': '0.0.0.0'})

class Root(object):
    @cherrypy.expose
    def index(self):
        return "Hello World!".encode('utf8')

root = Root()
cherrypy.quickstart(root)
}}}

=== Commands to run container ===
{{{#!highlight sh
docker build -t env-docker-cherry-image . 
# run container and map docker internal port 8081 to external port 8081
docker run -p 8081:8081 -d -it --rm --name env-docker-cherry-container --mount type=bind,source="$(pwd)"/target,target=/app env-docker-cherry-image
docker ps
# invoke external port 8081 
curl http://localhost:8081/
# change code in target ...
vi target/cherry.py # inside Root class
#    @cherrypy.expose
#    def test(self):
#        return "test hey!".encode('utf8')
# invoke external port 8081 to check the modification made
curl http://localhost:8081/test
#### create net between two containers
docker network create testnet
docker network ls
docker network connect testnet env-docker-cherry-container
docker run -p 8082:8081 -d -it --rm --name env-docker-cherry-container-2 --network testnet --mount type=bind,source="$(pwd)"/target,target=/app env-docker-cherry-image 
docker ps
docker exec -it env-docker-cherry-container-2 ash
# ping env-docker-cherry-container-2
# ping env-docker-cherry-container
docker exec -it env-docker-cherry-container ash
# ping env-docker-cherry-container-2
# ping env-docker-cherry-container
}}}

== Setup Proxy for docker daemon ==
{{{#!highlight sh
sudo bash
mkdir /etc/systemd/system/docker.service.d
cd  /etc/systemd/system/docker.service.d
nano http-proxy.conf
[Service]
Environment="HTTP_PROXY=http://192.168.22.214:3128"
Environment="HTTPS_PROXY=http://192.168.22.214:3128"
systemctl daemon-reload
systemctl restart docker

# settings also in ~/.docker/config.json
{
"proxies":
 {
   "default":
   {
     "httpProxy": "http://192.168.42.108:3128",
     "httpsProxy": "http://192.168.42.108:3128",
     "noProxy": "127.0.0.0/8"
   }
 }
}
}}}

== Install from binaries in Slackware 15.0 ==
{{{#!highlight sh
# as root
wget https://download.docker.com/linux/static/stable/x86_64/docker-20.10.17.tgz  
tar xvzf docker-20.10.17.tgz 
cp docker/* /usr/bin/ 
groupadd -r -g 281 docker 
usermod -a -G docker vitor
# signout and signin user vitor
sudo nohup dockerd & 
docker run hello-world
}}}

== Build image from scratch - Slackware64 15.0 - rootfs ==
=== Dockerfile ===
{{{#!highlight sh
FROM scratch
ADD . /
RUN /usr/bin/echo "test" > /test.txt 
#CMD ["/usr/bin/cat","/test.txt"]
CMD ["/usr/bin/tail","-f","/test.txt"]
}}}

=== Steps ===
{{{#!highlight sh 
mkdir scratch-test
cd scratch-test/
touch Dockerfile
mkdir -p usr/bin/
mkdir lib64
mkdir bin
cp /usr/bin/ls usr/bin/
cp /usr/bin/cat usr/bin/
cp /usr/bin/echo usr/bin/
cp /usr/bin/tail usr/bin/
cp /usr/bin/uname usr/bin/
cp /bin/sh bin/
# to check dependencies use ldd
cp /lib64/libcap.so.2 lib64/
cp /lib64/libc.so.6 lib64/
cp /lib64/libtinfo.so.6 lib64/
cp /lib64/libdl.so.2 lib64/
cp /lib64/ld-linux-x86-64.so.2 lib64/
# build image and run container
docker build -t scratch-test-image .
docker run --rm --name scratch-test-container scratch-test-image
#####
docker build -t scratch-test-image .
docker run -d --rm --name scratch-test-container  scratch-test-image
docker ps 
docker exec -it scratch-test-container sh 
# export container filesystem
docker container export scratch-test-container -o scratch-test.tar
tar tvf scratch-test.tar.gz 
}}}

== Static binaries in Slackware64 ==
 * https://docs.docker.com/engine/install/binaries/
 * https://download.docker.com/linux/static/stable/x86_64/docker-20.10.17.tgz

=== /etc/rc.d/rc.docker ===
{{{#!highlight sh
#!/bin/sh
PATH=$PATH:/usr/sbin

docker_start() {
  /usr/bin/dockerd --raw-logs > /var/log/dockerd.log 2>&1 &
}

docker_stop() {
  killall dockerd
}

docker_restart() {
  docker_stop
  docker_start
}

case "$1" in
'start')
  docker_start
  ;;
'stop')
  docker_stop
  ;;
'restart')
  docker_restart
  ;;
*)
  echo "usage $0 start|stop|restart"
esac
}}}

{{{#!highlight sh
# In Slack64
sudo sh /etc/rc.d/rc.docker start
#sudo sh /etc/rc.d/rc.docker stop
#sudo sh /etc/rc.d/rc.docker restart
docker ps
docker version 
docker run hello-world
}}}