Skip to content
This repository was archived by the owner on Aug 5, 2026. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions example/Dockerfile → Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@
FROM ubuntu:12.04
MAINTAINER Tom Arnfeld <tom@duedil.com>

REPOSITORY tarnfeld/portainer
BUILD_CPU 0.1
BUILD_MEM 512

# Install dependencies
RUN apt-get update && apt-get install -y build-essential git python-setuptools python-virtualenv

Expand Down
145 changes: 77 additions & 68 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@

# Portainer

Portainer is an [Apache Mesos](http://mesos.apache.org) framework that enables you to build docker images across a cluster of many machines. Given a valid `Dockerfile`, Portainer can build your image and push it to a private registry faster than you can count to `n`.

[![](http://img.shields.io/badge/duedil-hiring-green.svg)](http://duedil.careers/)
Portainer is an [Apache Mesos](http://mesos.apache.org) framework that enables you to build docker images across a cluster of many machines.

```
.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.
Expand All @@ -22,25 +20,14 @@ Portainer is an [Apache Mesos](http://mesos.apache.org) framework that enables y
, . ` , , , ,
.`.,,,,,,,,,.. ``````````````````````````````````````````````
` ,
``````` ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
```````````````````````````````` \
|¸.·´¯`·.´¯`·.¸¸.·´\ o o o o o o
| \
__|___|___|___|___|___| | \................................
|___|___|___|___| | (
___|___|___|___| | ) ( _/|_/ | |
|___|___|___| | ( ) <').-\ \/ Y
| ) ( `` | /!-!\ |
| ( ) \| |/
| ) ( _\___/_
| ( ) / / \ \
```````
```

When building docker images at scale, it can be time consuming and wasteful to manage dedicated infrastructure for building and pushing images. Building large containers with many sources and dependencies is a heavy operation, requiring large machines, and multiple of them. Deploying this infrastructure can be expensive and lead to poor utilization.
When building docker images at scale, it can be time consuming and wasteful to manage dedicated infrastructure for building and pushing images. Building large containers with many sources and dependencies is a heavy operation, sometimes requiring many large machines. Deploying this infrastructure can be expensive and often leads to poor utilization.

Given an existing Apache Mesos cluster, Portainer can get to work right away. If you're new to Mesos, you can try out the Vagrant box provided, or learn more about the [Apache Mesos Architecture](http://mesos.apache.org/documentation/latest/mesos-architecture/) and [get started](http://mesos.apache.org/gettingstarted/).

To use the Vagrant box, run `vagrant box add debian-73-x64-virtualbox-nocm http://puppet-vagrant-boxes.puppetlabs.com/debian-73-x64-virtualbox-nocm.box` then `vagrant up`
See below for more documentation on how to use the Vagrant virtual machine.

--------------------------------------------------------------------------------

Expand All @@ -49,95 +36,117 @@ To use the Vagrant box, run `vagrant box add debian-73-x64-virtualbox-nocm http:
- Works out of the box with existing `Dockerfile` files
- Configurable CPU/Memory resource limits for build tasks
- Full support for all `Dockerfile` commands, including local sources (e.g `ADD ./src`)
- Capable of building many images in parallel across the cluster
- Docker build logs are streamed from the Mesos slave for easy debugging and monitoring
- Docker build logs are streamed from the Mesos agent for easy debugging and monitoring
- Support for the `.dockerignore` file

#### Not Supported
#### Notes

- Pushing built images to the public docker index
- Pushing built images to the public docker index is currently not supported
- Support for docker client ~>1.7.0 requires Apache Mesos >=0.23.0 ([MESOS-3279](https://issues.apache.org/jira/browse/MESOS-3279))

--------------------------------------------------------------------------------

## Getting Started
## The Basics

### Framework Dependencies
### Dependencies

You'll need to have the following dependencies installed to run the framework, though it's likely you'll only need to install the ones highlighted in bold;
You'll need to have the following dependencies installed to run the framework.

- Python 2.7
- **Python `virtualenv` and `pip`**
- **Protocol Buffers (`brew install protobuf`)**
- Python `virtualenv` and `pip`
- Protocol Buffers (`brew install protobuf`)
- Make

### Slave Dependencies
### Mesos Agent Dependencies

By default, Portainer will try and launch an ephemeral docker daemon (`docker -d`) on the mesos agent machine using [docker in docker](github.com/jpetazzo/dind). This requires that you're using a Docker Containerizer on your Mesos agents. If you are not, you'll need to specify the `--docker-host` argument (e.g `--docker-host /var/run/docker.sock`) describing where the docker daemon can be accessed on each agent.

By default, Portainer will try and launch an ephemeral docker daemon (`docker -d`) on the mesos slave machine using [docker in docker](github.com/jpetazzo/dind). This requires that you're using a Docker Containerizer on your Mesos slaves. If you are not, you'll need to specify the `--docker-host` argument (e.g `--docker-host /var/run/docker.sock`) describing where the docker daemon can be accessed on each slave.
## Building an Image

*Note: Make sure you're on Mesos >=0.21.0 to allow for `privileged` containers.*
#### 1. Build/Upload the Executor

## Building Images
```
$ bin/build-executor
```

#### 1. Upload the Mesos executor
_Note: If you've got a dirty git tree, you'll need to set the `FORCE=1` environment variable._

Before being able to use Portainer, you need to upload the executor code somewhere accessible by the Mesos slaves. You can build a tar.gz archive containing the executor by running `bin/build-executor`. The archive will be dumped into `./dist/`, and needs to be uploaded somewhere Mesos can reach it (HDFS, S3, FTP, HTTP etc).
The built PEX (python executable) archive will be dumped into `./dist`, and needs to be uploaded somewhere Mesos can reach it (HDFS, S3, FTP, HTTP etc). Check the output from the build-executor command to see the file name, and upload the file.

The executor is a [pex](https://github.com/pantsbuild/pex) file, meaning it fully encapsulates all dependencies (other than python), and behaves like any old binary. Since some of portainer's dependencies are platform-specific, the pex file is, too. The environment name is tacked on to the archive filename, e.g. `portainer-37cc6d5eb334473fdaa9c7522c4ce585032dca5c.linux-x86_64.tar.gz`. Make sure you build the executor on the same platform as your mesos slaves use.
The environment name is tacked on to the archive filename, e.g. `dist/portainer-37cc6d5eb334473fdaa9c7522c4ce585032dca5c.linux-x86_64.tar.gz`. Make sure you build the executor on the same platform as your mesos slaves use.

In future, readily-downloadable prebuild pex files will be available on versioned github releases.

#### 2. Write your `Dockerfile`
#### 2. Grab a `Dockerfile`

Portainer can work out of the box on existing `Dockerfile` files with no modifications. To do this, you _must_ specify a repository for your image, using the `--repository` command line argument, for example`--repository duedil/portainer`.
Portainer can work out of the box on any existing `Dockerfile`. A few simple examples can be found in the `example/` directory, or you can build an image of the Portainer framework itself using the one at the root of this project directory.

You must also specify a private registry to push the image to once successfully built, using the `--to` command line argument, for example `--to my.registry:1234`.
#### 3. Local sources

If your `Dockerfile` is based upon a private image (in the `FROM` instruction) not available in the public docker index, you can use the `--from my.registry:1234` argument to configure where dependent images are pulled from. It is worth noting that when `--from` is used, all images are pulled from the given registry, and the public index is **never** used. This can be useful for mirroring public images which avoids being dependent on the public index.
If your `Dockerfile` does not include any local sources in the image (via `ADD` or `COPY`) you can skip this step.

Since Mesos is based around the concept of _Resources_, build tasks need some CPU and Memory to be able to execute. Defaults are provided, but the `--build-cpu` and `--build-mem` command line flags can be used to configure the resource allocation used.
Since Portainer will build your image on a remote machine, it must bundle and upload these local sources so they to be used remotely. Portainer uses a staging filesystem that can be accessed both by the framework and by the slave, this can be anything supported by the Mesos Fetcher (e.g HDFS).

--------------------------------------------------------------------------------
Use the `--staging-uri` command line flag to specify this. For example to distribute sources using your HDFS cluster, `--staging-uri=hdfs://my.namenode/tmp/portainer`.

As mentioned above, Portainer supports a set of custom `Dockerfile` instructions. These are safe to use with the standard `docker build` tool as they will simply be ignored.
#### 4. Invoke Portainer

- `REPOSITORY` / `--repository` - The name of the image repository (`string`)
- `BUILD_CPU` / `--build-cpu` - The number of CPUs required to build the image (`float`)
- `BUILD_MEM` / `--build-mem` - The amount of memory required to build the image (`integer`, in megabytes)
Given Portainer is an Apache Mesos framework, we need to define the resources we'd like to use to build our image. The CPU and RAM limits can be specified using the `--build-cpu` and `--build-mem` command line options. We also need to give our image a name (the repository), a tag and specify a registry to push to.

For an example, take a look at the `Dockerfile` provided in the `./example` folder. This can be used to build an image of the Portainer source code.
If you'd like to see the STDOUT/STDERR logs from your build printed live, add `--stream` to the list of arguments.

#### 3. Local `ADD` sources
```
$ cd portainer
$ ./bin/portainer \
--mesos-master "localhost:5050" \
--executor-uri "hdfs://my-namenode/path/to/portainer-executor.tar.gz" \
build \
--staging-uri "hdfs://my-namenode/tmp/portainer" \
--tag "latest" \
--to "my-registry:5000" \
--build-cpu 1 \
--build-mem 256 \
./Dockerfile
```

If your `Dockerfile` does not container any `ADD` commands that use local files, you can skip this step entirely. If you do use local sources, continue reading. Additional configuration is required.
## Vagrant Example

Docker provides a way of bundling up local sources into the image being built, using the `ADD` command. For example;
The vagrant virtual environment provided will launch a VM will the following components for testing out Portainer;

```
ADD ./src /usr/lib/my-src
```
- Mesos Master + Agent + ZooKeeper
- Docker Registry
- Mesos <> Docker Containerizer
- Portainer code

Since Portainer will build your image on a remote machine, it has to bundle and upload these local sources, so they to be used remotely when building the image. You can use any filesystem supported by [`pyfs`](github.com/duedil-ltd/pyfilesystem), including HDFS and S3. If you're using S3 you will need to configure the correct environment variables for authentication, being `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`.
### 1. Start the VM

Use the `--staging-uri` command line flag to specify this. For example to distribute sources using your HDFS cluster, `--staging-uri=hdfs://my.namenode:50070/tmp/portainer`.
To use the Vagrant box, run `vagrant box add debian-73-x64-virtualbox-nocm http://puppet-vagrant-boxes.puppetlabs.com/debian-73-x64-virtualbox-nocm.box` then `vagrant up` to set everything up.

*Note: Portainer imposes no restrictions on symlinks or relative paths in `ADD` instructions, unlike docker. In some situations this can pose security issues if building images from `Dockerfile` files from untrusted sources. Portainer and the Mesos executor will only have access to files readable to the user it's running as, so don't run the framework as `root`.*
### 2. Test Mesos

#### 4. Launch Portainer
The VM runs on a static IP `192.168.33.50` so before proceeding it's best to check that the Mesos UI is fully up and running at http://192.168.33.50:5050/ and there's a slave joined with at least 256MB of RAM. You should also check that the docker registry is up, a simple `docker ps` should demonstrate this.

Now that you've got everything set up, you're good to go. Because Portainer uses a pure-python implementation of the Mesos Framework API ([called pesos](http://github.com/wickman/pesos)), there is no requirement to install Apache Mesos itself to run the framework. You can use the invocation below as an example.
### 3. Build the executor

```
$ cd Portainer
$ ./bin/portainer \
--mesos-master "localhost:5050" \
--executor-uri "hdfs://my-namenode/path/to/portainer-executor.tar.gz" \
build \
--staging-uri "hdfs://my-namenode/tmp/portainer" \
--tag "my_custom_tag" \
--to "my-registry:5000" \
example/Dockerfile
```
To build the Portainer executor, simply run `bin/build-executor`.

_Note: If you've got a dirty git tree, you'll need to set the `FORCE=1` environment variable._

##### Debugging
### 4. Example build

To aid debugging, any exceptions thrown while building the docker image will be relayed back to the framework and printed out. If you want to keep an eye on the output of all `RUN` commands docker is executing while building your images, add the `--stream` argument and all stdout/stderr logs will be streamed to the framework.
You'll need to fill in a few blanks in the follow command line invocation, but this should start a simple build on the local mesos cluster, and push the image to the local repository.

```
$ bin/portainer \
--mesos-master 192.168.33.50:5050 \
build \
--staging-uri /tmp \
--executor-uri `pwd`/dist/portainer-{CHANGE THIS TO THE ACTUAL FILE}.tar.gz \
--to 192.168.33.50:5000 \
--build-cpu 0.1 \
--build-mem 256 \
--repository tarnfeld/portainer \
--tag latest \
--stream \
./Dockerfile
```
47 changes: 43 additions & 4 deletions Vagrantfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,50 @@
$docker_setup = <<SCRIPT
set -e

wget -q -O - http://get.docker.io/gpg | sudo apt-key add -
sudo bash -c "echo 'deb http://get.docker.io/ubuntu docker main' > /etc/apt/sources.list.d/docker.list"
sudo apt-get update -q
sudo apt-get install -q -y lxc-docker python-setuptools python-virtualenv
# Setup
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv E56151BF
DISTRO=$(lsb_release -is | tr '[:upper:]' '[:lower:]')
CODENAME=$(lsb_release -cs)

# Add the repository
echo "deb http://repos.mesosphere.io/${DISTRO} ${CODENAME} main" | \
sudo tee /etc/apt/sources.list.d/mesosphere.list
sudo apt-get -y update
sudo apt-get -y install mesos
sudo bash -c "echo 192.168.33.50 > /etc/mesos-master/ip"
sudo bash -c "echo 192.168.33.50 > /etc/mesos-slave/ip"
sudo bash -c "echo docker,mesos > /etc/mesos-slave/containerizers"
sudo bash -c "echo /usr/bin/docker-1.7.0 > /etc/mesos-slave/docker"

# Start a bunch of services
sudo service zookeeper restart
sleep 5
(sudo service mesos-master stop || true)
(sudo service mesos-slave stop || true)

# Install Docker
sudo bash -c 'echo "deb http://http.debian.net/debian wheezy-backports main" > /etc/apt/sources.list.d/backports.list'
sudo apt-get install -t wheezy-backports linux-image-amd64
curl -sSL https://get.docker.com/ | sh
sudo usermod -a -G docker vagrant

# Download a specific docker binary
# TODO: Skip the above?
sudo bash -c "curl -0 https://get.docker.com/builds/Linux/x86_64/docker-1.7.0 > /usr/bin/docker-1.7.0"

# Set up the docker registry
sudo mkdir -p /registry
sudo docker create -p 5000:5000 -v /registry:/tmp/registry-dev --name=registry registry:0.9.1
(sudo docker start registry || true)

# Start mesos
sudo service mesos-master start
sudo service mesos-slave start

# Install portainer dependencies
sudo apt-get install python-setuptools
sudo easy_install pip
sudo pip install virtualenv
SCRIPT

Vagrant.configure("2") do |config|
Expand Down
Loading