Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rebased the portus image to include puma #47

Merged
merged 1 commit into from
Mar 17, 2017
Merged
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
1 change: 1 addition & 0 deletions derived_images/portus/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
README.md
26 changes: 26 additions & 0 deletions derived_images/portus/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
FROM opensuse/amd64:42.2
MAINTAINER SUSE Containers Team <containers@suse.com>

# Install some helper scripts:
# 1. init: contains the entrypoint of this image.
# 2. check_db.rb: a rails runner used by the `init` script that checks
# if the database is up and running.
# 3. rpm-import-repo-key: temporary script that makes it easier to download
# and import gpg keys from trusted key servers. This is used later on to
# import the OBS key used to sign all the contents of the
# Virtualization:containers project.
COPY init check_db.rb rpm-import-repo-key /

# Install Portus and prepare the /certificates directory.
RUN /rpm-import-repo-key 55A0B34D49501BB7CA474F5AA193FBB572174FC2 && \
zypper ar -f obs://Virtualization:containers:Portus/openSUSE_Leap_42.2 portus && \
zypper ref && \
zypper -n in portus && \
zypper -n rm kbd-legacy && \
zypper clean -a && \
rm /rpm-import-repo-key && \
rm -rf /etc/pki/trust/anchors && \
ln -sf /certificates /etc/pki/trust/anchors

EXPOSE 3000
ENTRYPOINT ["/init"]
115 changes: 62 additions & 53 deletions derived_images/portus/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
The `docker` directory contains all the resources needed to create a
production-ready Docker image for Portus.
# Portus Official Docker image

This directory contains all the resources needed to create a production-ready
Docker image for Portus.

The master branch of this repository is going to include the files needed
to build Portus from HEAD. Other branches are available to build Portus out of
Expand All @@ -11,13 +13,12 @@ scheme: `portus-<release>`.
SUSE's containers team cares about security, hence we made the following
decisions:

* This image enforces the usage of HTTPS to access Portus.
* This image is running in the `production` environment, and because of that
SSL is enabled by default. You can disable this by setting the
`PORTUS_CHECK_SSL_USAGE_ENABLED` environment variable to false, but we don't
recommend this.
* Portus is installed from an RPM package, this ensures the final image will
have only the runtime dependency; no build time dependency is ever installed.
* The default user for this image is the `wwwrun` one, which is created by the
Apache package.
* The root account is locked, that means it's not possible to switch user via
`su` or `sudo`.

SUSE's containers team is constantly working to automate the release process
of Portus and of this image to ensure it stays up-to-date and secure.
Expand All @@ -27,40 +28,22 @@ certificates at runtime instead of adding them to a Docker image.

## Anatomy of the image

The image is based on openSUSE 42.1 and installs Portus using the RPM package
The image is based on openSUSE 42.2 and installs Portus using the RPM package
built by SUSE's containers team inside of the [Open Build Service](https://build.opensuse.org/project/subprojects/Virtualization:containers:Portus)
top level project and subprojects (one subproject per portus branch).

### Exposed ports

This image will use [Phusion Passenger](https://www.phusionpassenger.com/) in
conjunction with Apache to run Portus.

The container will expose the following ports:

* 443: this is used to serve the website over HTTPS.
* 80: most of the requests sent to this unencrypted channel will be
automatically redirected to the HTTPS channel.
The redirection is made using Apache's [mod_rewrite](https://httpd.apache.org/docs/current/mod/mod_rewrite.html).

The redirection from port 80 to port 443 applies to all the common requests sent
to Portus. The only requests that are **not** redirected are the ones sent to
the `v2/webhooks/events` endpoint. This is the endpoint used by the Docker
Registry to send notifications to Portus.

Sending Registry's notification to the HTTPS endpoint would require Portus'
certificate to be added to the Docker container running the registry. This is
not hard to be done, but involves some changes to the official Registry image
maintained by Docker Inc (or some hacks like a custom entrypoint added via a volume).
This image is using Puma as the web server and it only binds to the `3000`
port.

### The init script

As mentioned before, this Docker image has a init script which takes care of the
following actions:
This Docker image has a init script which takes care of the following actions:

1. Setup the database required by Portus
2. Import all the `.crt` located under `/certificates`
3. Start Apache
3. Start Puma

The next sections will provide more details about these steps.

Expand All @@ -87,51 +70,77 @@ by the upstream project.
### Secrets and certificates

Portus requires both a SSL key and a certificate to serve its contents over
HTTPS.
These files must be located here:

* SSL certificate file: `/certificates/portus-ca.crt`
* SSL certificate key file: `/secrets/portus.key`

The same key is also used to sign the JWT tokens issued to authenticate all the
docker clients against the Registry.
HTTPS. These files must be located in the `/certificates` directory of the
container. Moreover, it's up to the deployer to set the `PORTUS_PUMA_TLS_KEY`
and `PORTUS_PUMA_TLS_CERT` environment variables. Note that the key is also
used to sign the JWT tokens issued to authenticate all the docker clients
against the Registry.

It's also required to add the certificate of the Registry when the latter one
uses TLS to secure itself.
The Registry certificate must be placed inside of `/certificates`, the `init`
script of this image will automatically import it if it ends with the `.crt`
extension.
uses TLS to secure itself. The Registry certificate must be placed inside
of `/certificates`, the `init` script of this image will automatically import
it if it ends with the `.crt` extension.

### Logging

Both Portus' and Apache's messages are redirected to `stdout` and `stderr`. This
makes it possible to handle the logs of this image in the usual ways.
All logging is done to `stdout` and `stderr`. This makes it possible to handle
the logs of this image in the usual ways.

## Deployment

It's possible to deploy this image using one of the existing orchestration
solutions for Docker images.
solutions for Docker images. You can read some examples in the `examples`
directory of Portus' source code.

However we recommend the usage of [kubernetes](http://kubernetes.io/). We will
soon release a reference implementation.
### Executing the crono script

Portus uses [crono](https://github.com/plashchynski/crono) to handle some
background jobs. You can also execute this piece with this image. In order to do
this, you need to set the `PORTUS_INIT_COMMAND` environment variable to
"bin/crono".

### Environment variables

The following environment variables must be defined to run the image:
Here's the full list of environment variables:

Security related settings:

* `PORTUS_SECRET_KEY_BASE`: you can generate it using `openssl rand -hex 64`
* `PORTUS_PORTUS_PASSWORD`: you can generate it using `openssl rand -hex 64`
* `PORTUS_KEY_PATH`: the path of the certificate key. This is the key that
Portus will use for the authentication with your Docker registry.
* `PORTUS_PASSWORD`: the password of the hidden `portus` user. You can
generate it using `openssl rand -hex 64`
* `PORTUS_PUMA_TLS_KEY`: The TLS key to be picked by Puma.
* `PORTUS_PUMA_TLS_CERT`: The TLS certificate to be picked by Puma.
* `PORTUS_CHECK_SSL_USAGE_ENABLED`: Set this to `false` if you want to disable
SSL altogether.

Database releated settings:

* `MARIADB_SERVICE_HOST`: the host running the MariaDB database.
* `MARIADB_USER`: the database user to be used.
* `MARIADB_PASSWORD`: the password of the database user.
* `MARIADB_DATABASE`: the name of the Portus database.
* `PORTUS_PRODUCTION_HOST`: the host running the MariaDB database.
* `PORTUS_PRODUCTION_USERNAME`: the database user to be used.
* `PORTUS_PRODUCTION_PASSWORD`: the password of the database user.
* `PORTUS_PRODUCTION_DATABASE`: the name of the Portus database.

Deployment related settings:

* `PORTUS_MACHINE_FQDN_VALUE`: this is the fully qualified domain name of your
Portus instance (eg: `portus.example.com`).

Some fine tuning for Puma:

* `PORTUS_PUMA_WORKERS`: the amount of Puma workers to be spawned. Defaults to 1.
* `PORTUS_PUMA_MAX_THREADS`: the maximum amount of Puma threads to be
created. Defaults to 1.
* `RAILS_SERVE_STATIC_FILES`: set this to `true` if you want Puma to serve the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these default values enough to handle the case of Portus authenticating against itself (eg: the crono job scanning the contents of the registry). I remember some issues in the past caused by portus being stuck processing only one request at a time.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes for two reasons:

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My question is: wouldn't it be better to provide sane defaults for these environment variables to avoid our users to do the fine tuning?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that these defaults come from Portus' side actually 😃 I'll update that there

static files. Defaults to false, in which case you'd need for example NGinx
in front of this container.

Executing other commands:

* `PORTUS_INIT_COMMAND`: you can set this environment variable with the
command that you'd like to run. For example, if you want to run crono, you
can set it to "bin/crono".

You can also pass further environment variables to configure Portus as
described [here](http://port.us.org/docs/Configuring-Portus.html#override-specific-configuration-options).
63 changes: 0 additions & 63 deletions derived_images/portus/docker/Dockerfile

This file was deleted.

55 changes: 0 additions & 55 deletions derived_images/portus/docker/apache.conf

This file was deleted.

7 changes: 0 additions & 7 deletions derived_images/portus/docker/database.yml

This file was deleted.

4 changes: 0 additions & 4 deletions derived_images/portus/docker/secrets.yml

This file was deleted.

1 change: 0 additions & 1 deletion derived_images/portus/docker/start_apache2-sudoers

This file was deleted.

This file was deleted.

34 changes: 15 additions & 19 deletions derived_images/portus/docker/init → derived_images/portus/init
Original file line number Diff line number Diff line change
Expand Up @@ -51,24 +51,20 @@ setup_database() {
set -e
}

# ensure additional certificates (like the one of the docker registry)
# are known
sudo update-ca-certificates
# Ensure additional certificates (e.g. docker registry) are known.
update-ca-certificates

case "$1" in
# Further settings
export PORTUS_PUMA_HOST="0.0.0.0:3000"
export RACK_ENV="production"
export RAILS_ENV="production"
export GEM_PATH="/srv/Portus/vendor/bundle/ruby/2.1.0"

'portus')
setup_database
exec env sudo /usr/sbin/start_apache2 -DFOREGROUND -k start
;;

'crono')
cd /srv/Portus
RAILS_ENV=production exec bin/crono
;;

*)
exec "$@"
;;

esac
# Go to the Portus directory and execute the proper command.
cd /srv/Portus
if [ -z "$PORTUS_INIT_COMMAND" ]; then
setup_database
portusctl "pumactl -F /srv/Portus/config/puma.rb start"
else
portusctl "$PORTUS_INIT_COMMAND"
fi