Add a docker-in-docker container that will run the build server.
This commit is contained in:
parent
5d5d027cc0
commit
9dc9e0c940
5 changed files with 109 additions and 17 deletions
27
buildserver/Dockerfile
Normal file
27
buildserver/Dockerfile
Normal file
|
@ -0,0 +1,27 @@
|
|||
FROM lopter/raring-base
|
||||
MAINTAINER jake@devtable.com
|
||||
|
||||
RUN echo deb http://archive.ubuntu.com/ubuntu precise universe > /etc/apt/sources.list.d/universe.list
|
||||
RUN apt-get update -qq
|
||||
RUN apt-get install -qqy iptables ca-certificates lxc python-virtualenv git python-dev
|
||||
|
||||
# This will use the latest public release. To use your own, comment it out...
|
||||
ADD https://get.docker.io/builds/Linux/x86_64/docker-latest /usr/local/bin/docker
|
||||
# ...then uncomment the following line, and copy your docker binary to current dir.
|
||||
#ADD ./docker /usr/local/bin/docker
|
||||
|
||||
# Install the files
|
||||
ADD ./startserver /usr/local/bin/startserver
|
||||
ADD ./buildserver.py ./buildserver.py
|
||||
ADD ./test.html ./test.html
|
||||
ADD ./requirements-nover.txt ./requirements-nover.txt
|
||||
|
||||
RUN chmod +x /usr/local/bin/docker /usr/local/bin/startserver
|
||||
|
||||
RUN virtualenv --distribute venv
|
||||
RUN venv/bin/pip install -r requirements-nover.txt
|
||||
|
||||
VOLUME /var/lib/docker
|
||||
|
||||
EXPOSE 5002:5002
|
||||
CMD startserver
|
|
@ -1 +1,13 @@
|
|||
This must be run on Python version 2.7.4 or later (Ubuntu 13.04) for security reasons.
|
||||
To build:
|
||||
|
||||
```
|
||||
sudo docker build -t quay.io/quay/buildserver .
|
||||
sudo docker push quay.io/quay/buildserver
|
||||
```
|
||||
|
||||
To run:
|
||||
|
||||
```
|
||||
sudo docker pull quay.io/quay/buildserver
|
||||
sudo docker run -d -privileged -lxc-conf="aa_profile=unconfined" quay.io/quay/buildserver
|
||||
```
|
|
@ -54,16 +54,6 @@ def prepare_dockerfile(request_file):
|
|||
return build_dir
|
||||
|
||||
|
||||
MIME_PROCESSORS = {
|
||||
'application/zip': prepare_zip,
|
||||
'text/plain': prepare_dockerfile,
|
||||
}
|
||||
|
||||
|
||||
builds = {}
|
||||
pool = ThreadPool(1)
|
||||
|
||||
|
||||
def build_image(build_dir, tag_name, num_steps, result_object):
|
||||
try:
|
||||
logger.debug('Does this show up?')
|
||||
|
@ -106,11 +96,8 @@ def build_image(build_dir, tag_name, num_steps, result_object):
|
|||
current_image = 0
|
||||
image_progress = 0
|
||||
for status in resp:
|
||||
logger.debug(status)
|
||||
|
||||
if u'status' in status:
|
||||
status_msg = status[u'status']
|
||||
|
||||
next_image = r'(Pushing|Image) [a-z0-9]+( already pushed, skipping)?$'
|
||||
match = re.match(next_image, status_msg)
|
||||
if match:
|
||||
|
@ -141,7 +128,18 @@ def build_image(build_dir, tag_name, num_steps, result_object):
|
|||
result_object['message'] = e.message
|
||||
|
||||
|
||||
@app.route('/build', methods=['POST'])
|
||||
MIME_PROCESSORS = {
|
||||
'application/zip': prepare_zip,
|
||||
'text/plain': prepare_dockerfile,
|
||||
'application/octet-stream': prepare_dockerfile,
|
||||
}
|
||||
|
||||
|
||||
builds = {}
|
||||
pool = ThreadPool(1)
|
||||
|
||||
|
||||
@app.route('/build/', methods=['POST'])
|
||||
def start_build():
|
||||
docker_input = request.files['dockerfile']
|
||||
c_type = docker_input.content_type
|
||||
|
@ -180,7 +178,7 @@ def start_build():
|
|||
return redirect(url_for('get_status', job_id=job_id))
|
||||
|
||||
|
||||
@app.route('/status/<job_id>')
|
||||
@app.route('/build/<job_id>')
|
||||
def get_status(job_id):
|
||||
if job_id not in builds:
|
||||
abort(400)
|
||||
|
@ -188,6 +186,13 @@ def get_status(job_id):
|
|||
return jsonify(builds[job_id])
|
||||
|
||||
|
||||
@app.route('/build/', methods=['GET'])
|
||||
def get_all_status():
|
||||
return jsonify({
|
||||
'builds': builds,
|
||||
})
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
logging.basicConfig(level=logging.DEBUG, format=LOG_FORMAT)
|
||||
app.run(host='0.0.0.0', port=5002, debug=True)
|
48
buildserver/startserver
Normal file
48
buildserver/startserver
Normal file
|
@ -0,0 +1,48 @@
|
|||
#!/bin/bash
|
||||
|
||||
# First, make sure that cgroups are mounted correctly.
|
||||
CGROUP=/sys/fs/cgroup
|
||||
|
||||
[ -d $CGROUP ] ||
|
||||
mkdir $CGROUP
|
||||
|
||||
mountpoint -q $CGROUP ||
|
||||
mount -n -t tmpfs -o uid=0,gid=0,mode=0755 cgroup $CGROUP || {
|
||||
echo "Could not make a tmpfs mount. Did you use -privileged?"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Mount the cgroup hierarchies exactly as they are in the parent system.
|
||||
for SUBSYS in $(cut -d: -f2 /proc/1/cgroup)
|
||||
do
|
||||
[ -d $CGROUP/$SUBSYS ] || mkdir $CGROUP/$SUBSYS
|
||||
mountpoint -q $CGROUP/$SUBSYS ||
|
||||
mount -n -t cgroup -o $SUBSYS cgroup $CGROUP/$SUBSYS
|
||||
done
|
||||
|
||||
# Note: as I write those lines, the LXC userland tools cannot setup
|
||||
# a "sub-container" properly if the "devices" cgroup is not in its
|
||||
# own hierarchy. Let's detect this and issue a warning.
|
||||
grep -q :devices: /proc/1/cgroup ||
|
||||
echo "WARNING: the 'devices' cgroup should be in its own hierarchy."
|
||||
grep -qw devices /proc/1/cgroup ||
|
||||
echo "WARNING: it looks like the 'devices' cgroup is not mounted."
|
||||
|
||||
# Now, close extraneous file descriptors.
|
||||
pushd /proc/self/fd
|
||||
for FD in *
|
||||
do
|
||||
case "$FD" in
|
||||
# Keep stdin/stdout/stderr
|
||||
[012])
|
||||
;;
|
||||
# Nuke everything else
|
||||
*)
|
||||
eval exec "$FD>&-"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
popd
|
||||
|
||||
docker -d &
|
||||
exec venv/bin/python buildserver.py 2> buildserver.log
|
|
@ -1,6 +1,6 @@
|
|||
<html>
|
||||
<body>
|
||||
<form enctype='multipart/form-data' method="post" action="/build">
|
||||
<form enctype='multipart/form-data' method="post" action="/build/">
|
||||
<input type="file" name="dockerfile">
|
||||
<input type="text" name="tag">
|
||||
<button type="submit">Send</button>
|
||||
|
|
Reference in a new issue