As you probably remember from grade school math class, primes are numbers that are only divisible by 1 and themselves. 2, 3, 5, 7, and 11 are the first 5 prime numbers, for example.
Many computer operations, such as public-key cryptography, depends entirely on prime numbers. In fact, RSA encryption, invented in 1978, uses a modulo of a product of two very large primes for encryption and decryption. The security of asymmetric encryption is tightly coupled with the computational difficulty in factoring large numbers. I actually use prime numbers as the status update intervals in Byobu, in order to improve performance and distribute the update spikes.
Euclid proved that there are infinitely many prime numbers around 300 BC. But the Prime Number Theorem (proven in the 19th century) says that the probability of any number is prime is inversely proportional to its number of digits. That means that larger prime numbers are notoriously harder to find, and it gets harder as they get bigger!
What's the largest known prime number in the world?
Well, it has 17,425,170 decimal digits! If you wanted to print it out, size 11 font, it would take 6,543 pages -- or 14 reams of paper!
That number is actually one less than a very large power of 2. 257,885,161-1. It was discovered by Curtis Cooper on January 25, 2013, on an Intel Core2 Duo.
Actually, each of the last 14 record largest prime numbers discovered (between 1996 and today) have been of that form, 2P-1. Numbers of that form are called Mersenne Prime Numbers, named after Friar Marin Mersenne, a French priest who studied them in the 1600s.
Friar Mersenne's work continues today in the form of the Great Internet Mersenne Prime Search, and the mprime program, which has been used to find those 14 huge prime numbers since 1996.
mprime is a massive parallel, cpu scavenging utility, much like SETI@home or the Protein Folding Project. It runs in the background, consuming resources, working on its little piece of the problem. mprime is open source code, and also distributed as a statically compiled binary. And it will make a fine example of how to package a service into a Docker container, a Juju charm, and a Snappy snap.
Docker Container
First, let's build the Docker container, which will serve as our fundamental building block. You'll first need to download the mprime tarball from here. Extract it, and the directory structure should look a little like this (or you can browse it here):├── license.txt ├── local.txt ├── mprime ├── prime.log ├── prime.txt ├── readme.txt ├── results.txt ├── stress.txt ├── undoc.txt ├── whatsnew.txt └── worktodo.txt
And then, create a Dockerfile, that copies the files we need into the image. Here's our example.
FROM ubuntu MAINTAINER Dustin Kirkland email@example.com COPY ./mprime /opt/mprime/ COPY ./license.txt /opt/mprime/ COPY ./prime.txt /opt/mprime/ COPY ./readme.txt /opt/mprime/ COPY ./stress.txt /opt/mprime/ COPY ./undoc.txt /opt/mprime/ COPY ./whatsnew.txt /opt/mprime/ CMD ["/opt/mprime/mprime", "-w/opt/mprime/"]
Now, build your Docker image with:
$ sudo docker build . Sending build context to Docker daemon 36.02 MB Sending build context to Docker daemon Step 0 : FROM ubuntu ... Successfully built de2e817b195f
You can see that image, which I've publicly shared here: https://registry.hub.docker.com/u/kirkland/mprime/
Now you can run this image anywhere you can run Docker.
And verify that it's running:
Our directory structure for the charm looks like this (or you can browse it here):
Now you can run this image anywhere you can run Docker.
$ sudo docker run -d kirkland/mprime
And verify that it's running:
$ sudo docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES c9233f626c85 kirkland/mprime:latest "/opt/mprime/mprime 24 seconds ago Up 23 seconds furious_pike
Juju Charm
So now, let's create a Juju Charm that uses this Docker container. Actually, we're going to create a subordinate charm. Subordinate services in Juju are often monitoring and logging services, things that run along side primary services. Something like mprime is a good example of something that could be a subordinate service, attached to one or many other services in a Juju model.Our directory structure for the charm looks like this (or you can browse it here):
└── trusty └── mprime ├── config.yaml ├── copyright ├── hooks │ ├── config-changed │ ├── install │ ├── juju-info-relation-changed │ ├── juju-info-relation-departed │ ├── juju-info-relation-joined │ ├── start │ ├── stop │ └── upgrade-charm ├── icon.png ├── icon.svg ├── metadata.yaml ├── README.md └── revision 3 directories, 15 files
The three key files we should look at here are metadata.yaml, hooks/install and hooks/start:
$ cat metadata.yaml name: mprime summary: Search for Mersenne Prime numbers maintainer: Dustin Kirklanddescription: | A Mersenne prime is a prime of the form 2^P-1. The first Mersenne primes are 3, 7, 31, 127 (corresponding to P = 2, 3, 5, 7). There are only 48 known Mersenne primes, and the 13 largest known prime numbers in the world are all Mersenne primes. This charm uses a Docker image that includes the statically built, 64-bit Linux binary mprime which will consume considerable CPU and Memory, searching for the next Mersenne prime number. See http://www.mersenne.org/ for more details! tags: - misc subordinate: true requires: juju-info: interface: juju-info scope: container
$ cat hooks/install #!/bin/bash apt-get install -y docker.io docker pull kirkland/mprime
And:
$ cat hooks/start #!/bin/bash service docker restart docker run -d kirkland/mprime
Now, we can add the mprime service to any other running Juju service. As an example here, I'll --bootstrap, deploy the Apache2 charm, and attach mprime to it.
$ juju bootrap $ juju deploy apache2 $ juju deploy cs:~kirkland/mprime $ juju add-relation apache2 mprime
Looking at our services, we can see everything deployed and running here:
$ juju status services: apache2: charm: cs:trusty/apache2-14 exposed: false service-status: current: unknown since: 20 Jul 2015 11:55:59-05:00 relations: juju-info: - mprime units: apache2/0: workload-status: current: unknown since: 20 Jul 2015 11:55:59-05:00 agent-status: current: idle since: 20 Jul 2015 11:56:03-05:00 version: 1.24.2 agent-state: started agent-version: 1.24.2 machine: "1" public-address: 23.20.147.158 subordinates: mprime/0: workload-status: current: unknown since: 20 Jul 2015 11:58:52-05:00 agent-status: current: idle since: 20 Jul 2015 11:58:56-05:00 version: 1.24.2 agent-state: started agent-version: 1.24.2 upgrading-from: local:trusty/mprime-1 public-address: 23.20.147.158 mprime: charm: local:trusty/mprime-1 exposed: false service-status: {} relations: juju-info: - apache2 subordinate-to: - apache2
Snappy Ubuntu Core Snap
Finally, let's build a Snap. Snaps are applications that run in Ubuntu's transactional, atomic OS, Snappy Ubuntu Core.
We need the simple directory structure below (or you can browse it here):
The package.yaml describes what we're actually building, and what capabilities the service needs. It looks like this:
name: mprime
We need the simple directory structure below (or you can browse it here):
├── meta │ ├── icon.png │ ├── icon.svg │ ├── package.yaml │ └── readme.md └── start.sh 1 directory, 5 files
name: mprime
vendor: Dustin Kirklandarchitecture: [amd64] icon: meta/icon.png version: 28.5-11 frameworks: - docker services: - name: mprime description: "Search for Mersenne Prime Numbers" start: start.sh caps: - docker_client - networking
And the start.sh launches the service via Docker.
#!/bin/sh PATH=$PATH:/apps/docker/current/bin/ docker rm -v -f mprime docker run --name mprime -d kirkland/mprime docker wait mprime
Now, we can build the snap like so:
$ snappy build . Generated 'mprime_28.5-11_amd64.snap' snap $ ls -halF *snap -rw-rw-r-- 1 kirkland kirkland 9.6K Jul 20 12:38 mprime_28.5-11_amd64.snap
First, let's install the Docker framework, upon which we depend:
$ snappy-remote --url ssh://snappy-nuc install docker ======================================================= Installing docker from the store Installing docker Name Date Version Developer ubuntu-core 2015-04-23 2 ubuntu docker 2015-07-20 1.6.1.002 webdm 2015-04-23 0.5 sideload generic-amd64 2015-04-23 1.1 =======================================================
And now, we can install our locally built Snap.
$ snappy-remote --url ssh://snappy-nuc install mprime_28.5-11_amd64.snap ======================================================= Installing mprime_28.5-11_amd64.snap from local environment Installing /tmp/mprime_28.5-11_amd64.snap 2015/07/20 17:44:26 Signature check failed, but installing anyway as requested Name Date Version Developer ubuntu-core 2015-04-23 2 ubuntu docker 2015-07-20 1.6.1.002 mprime 2015-07-20 28.5-11 sideload webdm 2015-04-23 0.5 sideload generic-amd64 2015-04-23 1.1 =======================================================
Alternatively, you can install the snap directly from the Ubuntu Snappy store, where I've already uploaded the mprime snap:
$ snappy-remote --url ssh://snappy-nuc install mprime.kirkland ======================================================= Installing mprime.kirkland from the store Installing mprime.kirkland Name Date Version Developer ubuntu-core 2015-04-23 2 ubuntu docker 2015-07-20 1.6.1.002 mprime 2015-07-20 28.5-11 kirkland webdm 2015-04-23 0.5 sideload generic-amd64 2015-04-23 1.1 =======================================================
Conclusion
How long until this Docker image, Juju charm, or Ubuntu Snap finds a Mersenne Prime? Almost certainly never :-) I want to be clear: that was never the point of this exercise!Rather I hope you learned how easy it is to run a Docker image inside either a Juju charm or an Ubuntu snap. And maybe learned something about prime numbers along the way ;-)
Join us in #docker, #juju, and #snappy on irc.freenode.net.
Cheers,
Dustin
No comments:
Post a Comment
Please do not use blog comments for support requests! Blog comments do not scale well to this effect.
Instead, please use Launchpad for Bugs and StackExchange for Questions.
* bugs.launchpad.net
* stackexchange.com
Thanks,
:-Dustin