2017-04-25 16:45:34 +01:00
|
|
|
"""
|
|
|
|
Docker service allows running docker containers within CORE nodes.
|
2014-10-31 18:47:57 +00:00
|
|
|
|
|
|
|
The running of Docker within a CORE node allows for additional extensibility to
|
|
|
|
the CORE services. This allows network applications and protocols to be easily
|
|
|
|
packaged and run on any node.
|
|
|
|
|
|
|
|
This service that will add a new group to the services list. This
|
|
|
|
will have a service called Docker which will just start the docker service
|
|
|
|
within the node but not run anything. It will also scan all docker images on
|
|
|
|
the host machine. If any are tagged with 'core' then they will be added as a
|
|
|
|
service to the Docker group. The image will then be auto run if that service is
|
|
|
|
selected.
|
|
|
|
|
|
|
|
This requires a recent version of Docker. This was tested using a PPA on Ubuntu
|
2017-04-25 16:45:34 +01:00
|
|
|
with version 1.2.0. The version in the standard Ubuntu repo is to old for
|
2014-10-31 18:47:57 +00:00
|
|
|
this purpose (we need --net host).
|
|
|
|
|
|
|
|
It also requires docker-py (https://pypi.python.org/pypi/docker-py) which can be
|
|
|
|
installed with 'pip install docker-py'. This is used to interface with Docker
|
|
|
|
from the python service.
|
|
|
|
|
|
|
|
An example use case is to pull an image from Docker.com. A test image has been
|
|
|
|
uploaded for this purpose:
|
|
|
|
|
|
|
|
sudo docker pull stuartmarsden/multicastping
|
|
|
|
|
|
|
|
This downloads an image which is based on Ubuntu 14.04 with python and twisted.
|
|
|
|
It runs a simple program that sends a multicast ping and listens and records
|
|
|
|
any it receives.
|
|
|
|
|
|
|
|
In order for this to appear as a docker service it must be tagged with core.
|
|
|
|
Find out the id by running 'sudo docker images'. You should see all installed
|
|
|
|
images and the one you want looks like this:
|
|
|
|
|
|
|
|
stuartmarsden/multicastping latest 4833487e66d2 20 hours
|
|
|
|
ago 487 MB
|
|
|
|
|
|
|
|
The id will be different on your machine so use it in the following command:
|
|
|
|
|
|
|
|
sudo docker tag 4833487e66d2 stuartmarsden/multicastping:core
|
|
|
|
|
2017-04-25 16:45:34 +01:00
|
|
|
This image will be listed in the services after we restart the core-daemon:
|
2014-10-31 18:47:57 +00:00
|
|
|
|
|
|
|
sudo service core-daemon restart
|
|
|
|
|
|
|
|
You can set up a simple network with a number of PCs connected to a switch. Set
|
|
|
|
the stuartmarsden/multicastping service for all the PCs. When started they will
|
2017-04-25 16:45:34 +01:00
|
|
|
all begin sending Multicast pings.
|
2014-10-31 18:47:57 +00:00
|
|
|
|
|
|
|
In order to see what is happening you can go in to the terminal of a node and
|
|
|
|
look at the docker log. Easy shorthand is:
|
|
|
|
|
|
|
|
docker logs $(docker ps -q)
|
|
|
|
|
|
|
|
Which just shows the log of the running docker container (usually just one per
|
|
|
|
node). I have added this as an observer node to my setup: Name: docker logs
|
|
|
|
Command: bash -c 'docker logs $(docker ps -q) | tail -20'
|
|
|
|
|
|
|
|
So I can just hover over to see the log which looks like this:
|
|
|
|
|
|
|
|
Datagram 'Client: Ping' received from ('10.0.0.20', 8005)
|
|
|
|
Datagram 'Client: Ping' received from ('10.0.5.21', 8005)
|
|
|
|
Datagram 'Client: Ping' received from ('10.0.3.20', 8005)
|
|
|
|
Datagram 'Client: Ping' received from ('10.0.4.20', 8005)
|
|
|
|
Datagram 'Client: Ping' received from ('10.0.4.20', 8005)
|
|
|
|
Datagram 'Client: Ping' received from ('10.0.1.21', 8005)
|
|
|
|
Datagram 'Client: Ping' received from ('10.0.4.21', 8005)
|
|
|
|
Datagram 'Client: Ping' received from ('10.0.4.21', 8005)
|
|
|
|
Datagram 'Client: Ping' received from ('10.0.5.20', 8005)
|
|
|
|
Datagram 'Client: Ping' received from ('10.0.0.21', 8005)
|
|
|
|
Datagram 'Client: Ping' received from ('10.0.3.21', 8005)
|
|
|
|
Datagram 'Client: Ping' received from ('10.0.0.20', 8005)
|
|
|
|
Datagram 'Client: Ping' received from ('10.0.5.21', 8005)
|
|
|
|
Datagram 'Client: Ping' received from ('10.0.3.20', 8005)
|
|
|
|
Datagram 'Client: Ping' received from ('10.0.4.20', 8005)
|
|
|
|
Datagram 'Client: Ping' received from ('10.0.4.20', 8005)
|
|
|
|
Datagram 'Client: Ping' received from ('10.0.1.21', 8005)
|
|
|
|
Datagram 'Client: Ping' received from ('10.0.4.21', 8005)
|
|
|
|
Datagram 'Client: Ping' received from ('10.0.4.21', 8005)
|
|
|
|
Datagram 'Client: Ping' received from ('10.0.5.20', 8005)
|
|
|
|
|
|
|
|
Limitations:
|
|
|
|
|
2017-04-25 16:45:34 +01:00
|
|
|
1. Docker images must be downloaded on the host as usually a CORE node does not
|
2014-10-31 18:47:57 +00:00
|
|
|
have access to the internet.
|
|
|
|
2. Each node isolates running containers (keeps things simple)
|
2017-04-25 16:45:34 +01:00
|
|
|
3. Recent version of docker needed so that --net host can be used. This does
|
|
|
|
not further abstract the network within a node and allows multicast which
|
2014-10-31 18:47:57 +00:00
|
|
|
is not enabled within Docker containers at the moment.
|
|
|
|
4. The core-daemon must be restarted for new images to show up.
|
|
|
|
5. A Docker-daemon is run within each node but the images are shared. This
|
|
|
|
does mean that the daemon attempts to access an SQLlite database within the
|
|
|
|
host. At startup all the nodes will try to access this and it will be locked
|
|
|
|
for most due to contention. The service just does a hackish wait for 1 second
|
|
|
|
and retry. This means all the docker containers can take a while to come up
|
2017-04-25 16:45:34 +01:00
|
|
|
depending on how many nodes you have.
|
|
|
|
"""
|
2014-10-31 18:47:57 +00:00
|
|
|
|
2017-08-07 19:58:51 +01:00
|
|
|
from core import logger
|
2017-04-25 16:45:34 +01:00
|
|
|
from core.service import CoreService
|
|
|
|
from core.service import ServiceManager
|
|
|
|
|
2014-10-31 18:47:57 +00:00
|
|
|
try:
|
|
|
|
from docker import Client
|
2017-04-25 16:45:34 +01:00
|
|
|
except ImportError:
|
2018-06-22 16:16:59 +01:00
|
|
|
logger.warn("missing python docker bindings")
|
2014-10-31 18:47:57 +00:00
|
|
|
|
|
|
|
|
|
|
|
class DockerService(CoreService):
|
2017-04-25 16:45:34 +01:00
|
|
|
"""
|
|
|
|
This is a service which will allow running docker containers in a CORE
|
|
|
|
node.
|
|
|
|
"""
|
2018-06-15 22:03:27 +01:00
|
|
|
name = "Docker"
|
2018-06-19 17:19:49 +01:00
|
|
|
executables = ("docker",)
|
2018-06-15 22:03:27 +01:00
|
|
|
group = "Docker"
|
|
|
|
dirs = ('/var/lib/docker/containers/', '/run/shm', '/run/resolvconf',)
|
|
|
|
configs = ('docker.sh',)
|
|
|
|
startup = ('sh docker.sh',)
|
|
|
|
shutdown = ('service docker stop',)
|
2014-10-31 18:47:57 +00:00
|
|
|
# Container image to start
|
2018-06-15 22:03:27 +01:00
|
|
|
image = ""
|
2014-10-31 18:47:57 +00:00
|
|
|
|
|
|
|
@classmethod
|
2018-06-22 23:47:02 +01:00
|
|
|
def generate_config(cls, node, filename):
|
2017-04-25 16:45:34 +01:00
|
|
|
"""
|
|
|
|
Returns a string having contents of a docker.sh script that
|
|
|
|
can be modified to start a specific docker image.
|
|
|
|
"""
|
2014-10-31 18:47:57 +00:00
|
|
|
cfg = "#!/bin/sh\n"
|
|
|
|
cfg += "# auto-generated by Docker (docker.py)\n"
|
2017-04-25 16:45:34 +01:00
|
|
|
# Docker likes to think it has DNS set up or it complains.
|
2014-10-31 18:47:57 +00:00
|
|
|
# Unless your network was attached to the Internet this is
|
|
|
|
# non-functional but hides error messages.
|
|
|
|
cfg += 'echo "nameserver 8.8.8.8" > /run/resolvconf/resolv.conf\n'
|
|
|
|
# Starts the docker service. In Ubuntu this is docker.io; in other
|
|
|
|
# distros may just be docker
|
|
|
|
cfg += 'service docker start\n'
|
|
|
|
cfg += "# you could add a command to start a image here eg:\n"
|
2018-06-15 22:03:27 +01:00
|
|
|
if not cls.image:
|
2014-10-31 18:47:57 +00:00
|
|
|
cfg += "# docker run -d --net host --name coreDock <imagename>\n"
|
|
|
|
else:
|
|
|
|
cfg += """\
|
|
|
|
result=1
|
|
|
|
until [ $result -eq 0 ]; do
|
|
|
|
docker run -d --net host --name coreDock %s
|
|
|
|
result=$?
|
|
|
|
# this is to alleviate contention to docker's SQLite database
|
|
|
|
sleep 0.3
|
|
|
|
done
|
2018-06-15 22:03:27 +01:00
|
|
|
""" % (cls.image,)
|
2014-10-31 18:47:57 +00:00
|
|
|
return cfg
|
|
|
|
|
2017-08-08 00:40:39 +01:00
|
|
|
@classmethod
|
|
|
|
def on_load(cls):
|
|
|
|
logger.debug("loading custom docker services")
|
|
|
|
|
|
|
|
if "Client" in globals():
|
|
|
|
client = Client(version="1.10")
|
|
|
|
images = client.images()
|
|
|
|
del client
|
|
|
|
else:
|
|
|
|
images = []
|
2017-04-25 16:45:34 +01:00
|
|
|
|
2017-08-08 00:40:39 +01:00
|
|
|
for image in images:
|
|
|
|
if u"<none>" in image["RepoTags"][0]:
|
2017-04-25 16:45:34 +01:00
|
|
|
continue
|
2017-08-08 00:40:39 +01:00
|
|
|
for repo in image["RepoTags"]:
|
|
|
|
if u":core" not in repo:
|
|
|
|
continue
|
|
|
|
dockerid = repo.encode("ascii", "ignore").split(":")[0]
|
|
|
|
sub_class = type("SubClass", (DockerService,), {"_name": dockerid, "_image": dockerid})
|
|
|
|
ServiceManager.add(sub_class)
|
|
|
|
|
|
|
|
del images
|