Build Docker Base Image for CentOS 7.x

… (with tweak for running without nested virtualization)

Environment Setup

Linux VM – CentOS 7.3 Minimal
– SELINUX Disabled
– Firewall Disabled

Step #1a: Install Docker

curl -sfo /etc/yum.repos.d/docker-ce.repo
yum install -y epel-release docker-ce 
systemctl enable docker
systemctl start docker

Step #1b: Install build tools

yum install -y lorax anaconda-tui

Build the Image

Step #2: Generate the tarball

mkdir -p docker-dev-centos && cd docker-dev-centos

curl -sO

curl -sO

### prevent CentOS 7.3 from installing open-vm-tools-desktop
sed -i '/yum-plugin-ovl/a @platform-vmware --nodefaults' centos-7.ks

livemedia-creator --make-tar --no-virt \
--iso=CentOS-7-x86_64-NetInstall-1611.iso \
--ks=centos-7.ks \

When installing RHEL 7.3 as a vmware guest, the installer (Anaconda) automatically detects the virtualization host, then installs the VMware Tools (irrelevant for containers).
@TWEAK – ref:

Step #3a: Import tarball (no tag)

cat /var/tmp/centos-root.tar.xz | docker import - mycentos

Step #3b: Import tarball (with tag=datestamp)

STAMP=$(date +%Y-%m-%d)
cat /var/tmp/centos-root.tar.xz | docker import - mycentos:$STAMP
docker tag mycentos:$STAMP mycentos

Test the Image

docker run -it --rm mycentos /bin/bash

[root@05eaed83571f /]# rpm -qa | wc -l

Query packages

docker run -it --rm mycentos rpm -qa --queryformat "%{NAME}\t%{VERSION}\t%{RELEASE}\t%{ARCH}\n"


Minimal Mesosphere DC/OS v1.9 (Single)

… (with tweak for running a tiny marathon-lb on the slave node)


Mesosphere DC/OS is built on top of Apache Mesos, which is a leading open-source framework for distributed applications. The key design differentiation is its two-level scheduler which enables it to handle complex workloads like big-data analytics, grid computing, etc.

The official recommendation for a lab-install is Vagrant, which may not be available in many big enterprise environments (for obvious reasons).

In this article, we’ll go over the procedure for setting up a tiny DC/OS cluster using a Single VM and demonstration of basic orchestration capability using Marathon framework.


  • One VM only! (for a resource constrained lab or laptop)
  • CentOS 7.3 Minimal + SELINUX Disabled + Firewall Disabled + IPv6 Disabled
  • Docker (docker-ce 17.06.0.ce)


Host Role VM Size
mesos-single bootstrap + master + slave + dcos-cli 2 CPU, 6GB RAM, 60GB HDD


NOTE: set proxy related environment variables if needed.

# only if proxy is needed
export http_proxy=""
export https_proxy=""
# get yum repo for docker-ce
curl -sfo /etc/yum.repos.d/docker-ce.repo

# install docker-ce and other required packages
yum install -y epel-release docker-ce tar xz unzip curl ipset chrony
groupadd nogroup
# clean yum cache (optional)
yum clean all

# only if proxy is needed
# proxy needed - start
mkdir -p /etc/systemd/system/docker.service.d

cat > /etc/systemd/system/docker.service.d/override.conf << '__EOF__'

systemctl daemon-reload
# proxy needed - end

# enable and start docker
systemctl enable docker
systemctl start docker

# add to host file if DNS doesn't resolve the hostname
tee -a /etc/hosts << '__EOF__' mesos-single

To be run for bootstrap

Generate bootstrap

# create setup directory, download the install binary
mkdir /opt/dcos-setup && cd /opt/dcos-setup && curl -O

# create config directory 
mkdir -p genconf

# create ip-detect script; change 'ens192' if needed
cat > genconf/ip-detect << '__EOF__'
#!/usr/bin/env bash
set -o nounset -o errexit
export PATH=/usr/sbin:/usr/bin:$PATH
echo $(ip addr show ens192 | grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | head -1)
chmod 755 genconf/ip-detect

### VERY IMPORTANT: validate that the following ip-detect is working
### if not then follow
###   to get a working script, must work consistently on this node

# configuration yaml
cat > genconf/config.yaml << '__EOF__'
bootstrap_url: http://mesos-single:8081       
cluster_name: dcos
exhibitor_storage_backend: static
master_discovery: static
telemetry_enabled: 'false'
# only if proxy is needed
use_proxy: 'true'
- localhost
- '*'

# generate bootstarp

Launch bootstrap

# serve the bootstrap code-base using tiny nginx (alpine based)
docker pull nginx:alpine
docker run -d --restart=unless-stopped -p 8081:80 -v /opt/dcos-setup/genconf/serve:/usr/share/nginx/html:ro --name=dcos-bootstrap-nginx nginx:alpine

To be run for {master}

mkdir -p /tmp/dcos && cd /tmp/dcos && curl -O --noproxy '*' http://mesos-single:8081/ && bash master && cd -

The installation progress can be seen at exhibitor URL i.e.

Install dcos-cli (while we are waiting for the master to come up).

mkdir -p ~/bin && cd ~/bin && curl -sfO && chmod 755 ~/bin/dcos && cd -

dcos config set core.dcos_url
dcos auth login

To be run for {slave}

NOTE: this is the tweak for running slave on the master node (not supported officially, may break in the future release).

export opt_mesos=$(ls -1d /opt/mesosphere/packages/mesos--*)
ln -s $opt_mesos/ /etc/systemd/system
ln -s $opt_mesos/ /etc/systemd/system/
systemctl start dcos-mesos-slave


Browse to (when ready – usually takes 5-to-10 minutes)

DC/OS v1.9 UI

Install the tiny marathon-lb (0.1 CPU, 128mb RAM)

IMPORTANT: dcos package based install won’t allow our proposed tiny configuration, so we’ll use marathon!

Export marathon json

# allows to run on slave and skip port 80+443 binding
cat > marathon-lb-internal.json << '__EOF__'
{ "marathon-lb":{ "name": "marathon-lb-internal", "instances": 1, "haproxy-group": "internal", "role": "", "bind-http-https": false} }
# export the marathon configuration (for tweaking)
dcos package describe --app --render marathon-lb --options=marathon-lb-internal.json > marathon-lb.json

Edit the json, use sed or manually edit it
Set cpu to 0.1 and mem to 128 (more than enough for a demo setup)

sed -i 's/"cpus": 2/"cpus": 0.1/' marathon-lb.json
sed -i 's/ "mem": 1024/ "mem": 128/' marathon-lb.json

Let marathon deploy this app

dcos marathon app add marathon-lb.json

Install the demo app (dockercloud/hello-world)

Our demo app for this setup is dockercloud/hello-world

cat > dockercloud-hello-world.json << '__EOF__'
  "id": "dockercloud-hello-world",
  "container": {
    "type": "DOCKER",
    "docker": {
      "image": "dockercloud/hello-world",
      "network": "BRIDGE",
      "portMappings": [
        { "hostPort": 0, "containerPort": 80, "servicePort":10000 }
  "instances": 2,
  "cpus": 0.1,
  "mem": 128,
  "healthChecks": [{
      "protocol": "HTTP",
      "path": "/",
      "portIndex": 0,
      "timeoutSeconds": 10,
      "gracePeriodSeconds": 10,
      "intervalSeconds": 2,
      "maxConsecutiveFailures": 10

# deploy the demo app
dcos marathon app add dockercloud-hello-world.json

Browse to =>

or run the follwoing command

for i in $(seq 1 5); do curl -sf | grep -oP "My hostname is [0-9,a-z]+"; done


My hostname is 705bc9fdf535
My hostname is d74cf174fff0
My hostname is 705bc9fdf535
My hostname is d74cf174fff0
My hostname is 705bc9fdf535


The single node DC/OS setup has a lower (roughly 3gb) resource/memory overhead and can be great for learning and tryout simple container / micro-service workloads. It is possible to run additional non-distributed frameworks (like Jenkins) if adequate RAM is available.

Have fun!