Code Monkey home page Code Monkey logo

passenger-docker's Introduction

Docker base images for Ruby, Python, Node.js and Meteor web apps

Docker

Passenger-docker is a set of Docker images meant to serve as good bases for Ruby, Python, Node.js and Meteor web app images. In line with Phusion Passenger's goal, passenger-docker's goal is to make Docker image building for web apps much easier and faster.

Why is this image called "passenger"? It's to represent the ease: you just have to sit back and watch most of the heavy lifting being done for you. Passenger-docker is part of a larger and more ambitious project: to make web app deployment ridiculously simple, to heights never achieved before.

Relevant links: Github | Docker registry | Discussion forum | Twitter/X | Blog


Table of contents


Why use passenger-docker?

Why use passenger-docker instead of doing everything yourself in Dockerfile?

  • Your Dockerfile can be smaller.
  • It reduces the time needed to write a correct Dockerfile. You won't have to worry about the base system and the stack, you can focus on just your app.
  • It sets up the base system correctly. It's very easy to get the base system wrong, but this image does everything correctly. Learn more.
  • It drastically reduces the time needed to run docker build, allowing you to iterate your Dockerfile more quickly.
  • It reduces download time during redeploys. Docker only needs to download the base image once: during the first deploy. On every subsequent deploys, only the changes you make on top of the base image are downloaded.

About the image

What's included?

Passenger-docker is built on top of a solid base: baseimage-docker.

Basics (learn more at baseimage-docker):

  • Ubuntu 22.04 LTS as base system.
  • A correct init process (learn more).
  • Fixes APT incompatibilities with Docker.
  • syslog-ng.
  • The cron daemon.
  • Runit for service supervision and management.

Language support:

  • Ruby 3.1.6, 3.2.4, 3.3.3 and JRuby 9.3.14.0 and 9.4.6.0.
    • RVM is used to manage Ruby versions. Why RVM?
    • 3.3.3 is configured as the default.
    • JRuby is installed from source, but we register an APT entry for it.
    • JRuby uses OpenJDK 17.
  • Python 2.7 or 3.10, or any version provided by the Deadsnakes PPA (currently 3.7, 3.8, 3.9, 3.11, and 3.12; see https://launchpad.net/~deadsnakes/+archive/ubuntu/ppa).
  • Node.js 18 by default, or any version provided by Nodesource (currently 16, 18, 20, 21; see https://github.com/nodesource/distributions).
  • A build system, git, and development headers for many popular libraries, so that the most popular Ruby, Python and Node.js native extensions can be compiled without problems.

Web server and application server:

  • Nginx 1.18. Disabled by default.
  • Phusion Passenger 6. Disabled by default (because it starts along with Nginx).
    • This is a fast and lightweight tool for simplifying web application integration into Nginx.
    • It adds many production-grade features, such as process monitoring, administration and status inspection.
    • It replaces (G)Unicorn, Thin, Puma, uWSGI.
    • Node.js users: watch this 4 minute intro video to learn why it's cool and useful.

Auxiliary services and tools:

  • Redis 6.0. Not installed by default.
  • Memcached. Not installed by default.

Memory efficiency

Passenger-docker is very lightweight on memory. In its default configuration, it only uses 10 MB of memory (the memory consumed by bash, runit, syslog-ng, etc).

Image variants

Passenger-docker consists of several images, each one tailor made for a specific user group.

Ruby images

  • phusion/passenger-ruby31 - Ruby 3.1.
  • phusion/passenger-ruby32 - Ruby 3.2.
  • phusion/passenger-ruby33 - Ruby 3.3.
  • phusion/passenger-jruby93 - JRuby 9.3.
  • phusion/passenger-jruby94 - JRuby 9.4.

Python images

  • phusion/passenger-python38 - Python 3.8
  • phusion/passenger-python39 - Python 3.9
  • phusion/passenger-python310 - Python 3.10
  • phusion/passenger-python311 - Python 3.11
  • phusion/passenger-python312 - Python 3.12

Node.js and Meteor images

  • phusion/passenger-nodejs - Node.js 18.

Other images

  • phusion/passenger-full - Contains everything in the above images. Ruby, Python, Node.js, all in a single image for your convenience.
  • phusion/passenger-customizable - Contains only the base system, as described in "What's included?". Specific Ruby, Python, and Node.js versions are not preinstalled beyond what is needed for the image to run, or which are inherited from the baseimage. This image is meant to be further customized through your Dockerfile. For example, using this image you can create a custom image that contains Ruby 3.2 and Node.js.

In the rest of this document we're going to assume that the reader will be using phusion/passenger-full, unless otherwise stated. Simply substitute the name if you wish to use another image.

Inspecting the image

To look around in the image, run:

docker run --rm -t -i phusion/passenger-full bash -l

You don't have to download anything manually. The above command will automatically pull the passenger-docker image from the Docker registry.

Using the image as base

Getting started

There are several images, e.g. phusion/passenger-ruby32 and phusion/passenger-nodejs. Choose the one you want. See Image variants.

So put the following in your Dockerfile:

# Use phusion/passenger-full as base image. To make your builds reproducible, make
# sure you lock down to a specific version, not to `latest`!
# See https://github.com/phusion/passenger-docker/blob/master/CHANGELOG.md for
# a list of version numbers.
FROM phusion/passenger-full:<VERSION>
# Or, instead of the 'full' variant, use one of these:
#FROM phusion/passenger-ruby31:<VERSION>
#FROM phusion/passenger-ruby32:<VERSION>
#FROM phusion/passenger-ruby33:<VERSION>
#FROM phusion/passenger-python38:<VERSION>
#FROM phusion/passenger-python39:<VERSION>
#FROM phusion/passenger-python310:<VERSION>
#FROM phusion/passenger-python311:<VERSION>
#FROM phusion/passenger-python312:<VERSION>
#FROM phusion/passenger-jruby93:<VERSION>
#FROM phusion/passenger-jruby94:<VERSION>
#FROM phusion/passenger-nodejs:<VERSION>
#FROM phusion/passenger-customizable:<VERSION>

# Set correct environment variables.
ENV HOME /root

# Use baseimage-docker's init process.
CMD ["/sbin/my_init"]

# If you're using the 'customizable' variant, you need to explicitly opt-in
# for features.
#
# N.B. these images are based on https://github.com/phusion/baseimage-docker,
# so anything it provides is also automatically on board in the images below
# (e.g. older versions of Ruby, Node, Python).
#
# Uncomment the features you want:
#
#   Node.js and Meteor standalone support (not needed if you will also be installing Ruby, unless you need a version other than the default)
#RUN /pd_build/nodejs.sh 18
#
#   Ruby support
#RUN /pd_build/ruby-3.1.*.sh
#RUN /pd_build/ruby-3.2.*.sh
#RUN /pd_build/ruby-3.3.*.sh
#RUN /pd_build/jruby-9.3.*.sh
#RUN /pd_build/jruby-9.4.*.sh
#
#   Python support
#RUN /pd_build/python.sh 3.10

# ...put your own build instructions here...

# Clean up APT when done.
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

The app user

The image has an app user with UID 9999 and home directory /home/app. Your application is supposed to run as this user. Even though Docker itself provides some isolation from the host OS, running applications without root privileges is good security practice.

Your application should be placed inside /home/app.

Note: when copying your application, make sure to set the ownership of the application directory to app by calling COPY --chown=app:app /local/path/of/your/app /home/app/webapp

Using Nginx and Passenger

Before using Passenger, you should familiarise yourself with it by reading its documentation.

Nginx and Passenger are disabled by default. Enable them like so:

RUN rm -f /etc/service/nginx/down

Adding your web app to the image

Passenger works like a mod_ruby, mod_nodejs, etc. It changes Nginx into an application server and runs your app from Nginx. So to get your web app up and running, you just have to add a virtual host entry to Nginx which describes where you app is, and Passenger will take care of the rest.

You can add a virtual host entry (server block) by placing a .conf file in the directory /etc/nginx/sites-enabled. For example:

/etc/nginx/sites-enabled/webapp.conf:

server {
    listen 80;
    server_name www.webapp.com;
    root /home/app/webapp/public;

    # The following deploys your Ruby/Python/Node.js/Meteor app on Passenger.

    # Not familiar with Passenger, and used (G)Unicorn/Thin/Puma/pure Node before?
    # Yes, this is all you need to deploy on Passenger! All the reverse proxying,
    # socket setup, process management, etc are all taken care automatically for
    # you! Learn more at https://www.phusionpassenger.com/.
    passenger_enabled on;
    passenger_user app;

    # If this is a Ruby app, specify a Ruby version:
    # For Ruby 3.3
    passenger_ruby /usr/bin/ruby3.3;
    # For Ruby 3.2
    passenger_ruby /usr/bin/ruby3.2;
    # For Ruby 3.1
    passenger_ruby /usr/bin/ruby3.1;

    # For Python ie. Django
    passenger_app_type wsgi;
    passenger_startup_file passenger_wsgi.py; (contents example: https://gist.github.com/ajhodgson/96c51dba349697e5c7e46027cc530434)

    # For Node.js
    passenger_app_type node;
    passenger_startup_file app.js;

    # Nginx has a default limit of 1 MB for request bodies, which also applies
    # to file uploads. The following line enables uploads of up to 50 MB:
    client_max_body_size 50M;
}

Dockerfile:

RUN rm /etc/nginx/sites-enabled/default
ADD webapp.conf /etc/nginx/sites-enabled/webapp.conf
RUN mkdir /home/app/webapp
RUN ...commands to place your web app in /home/app/webapp...
# This copies your web app with the correct ownership.
# COPY --chown=app:app /local/path/of/your/app /home/app/webapp

Configuring Nginx

The best way to configure Nginx is by adding .conf files to /etc/nginx/main.d and /etc/nginx/conf.d. Files in main.d are included into the Nginx configuration's main context, while files in conf.d are included in the Nginx configuration's http context.

For example:

# /etc/nginx/main.d/secret_key.conf:
env SECRET_KEY=123456;

# /etc/nginx/conf.d/gzip_max.conf:
gzip_comp_level 9;

# Dockerfile:
ADD secret_key.conf /etc/nginx/main.d/secret_key.conf
ADD gzip_max.conf /etc/nginx/conf.d/gzip_max.conf

Setting environment variables in Nginx

By default Nginx clears all environment variables (except TZ) for its child processes (Passenger being one of them). That's why any environment variables you set with docker run -e, Docker linking and /etc/container_environment, won't reach Nginx.

To preserve these variables, place an Nginx config file ending with *.conf in the directory /etc/nginx/main.d, in which you tell Nginx to preserve these variables. For example when linking a PostgreSQL container or MongoDB container:

# /etc/nginx/main.d/postgres-env.conf:
env POSTGRES_PORT_5432_TCP_ADDR;
env POSTGRES_PORT_5432_TCP_PORT;

# Dockerfile:
ADD postgres-env.conf /etc/nginx/main.d/postgres-env.conf

By default, passenger-docker already contains a config file /etc/nginx/main.d/default.conf which preserves the PATH environment variable.

Application environment name (RAILS_ENV, NODE_ENV, etc)

Some web frameworks adjust their behavior according to the value some environment variables. For example, Rails respects RAILS_ENV while Connect.js respects NODE_ENV. By default, Phusion Passenger sets all of the following environment variables to the value production:

  • RAILS_ENV
  • RACK_ENV
  • WSGI_ENV
  • NODE_ENV
  • PASSENGER_APP_ENV

Setting these environment variables yourself (e.g. using docker run -e RAILS_ENV=...) will not have any effect, because Phusion Passenger overrides all of these environment variables. The only exception is PASSENGER_APP_ENV (see below).

With passenger-docker, there are two ways to set the aforementioned environment variables. The first is through the passenger_app_env config option in Nginx. For example:

# /etc/nginx/sites-enabled/webapp.conf:
server {
    ...
    # Ensures that RAILS_ENV, NODE_ENV, etc are set to "staging"
    # when your application is started.
    passenger_app_env staging;
}

The second way is by setting the PASSENGER_APP_ENV environment variable from docker run

docker run -e PASSENGER_APP_ENV=staging YOUR_IMAGE

This works because passenger-docker autogenerates an Nginx configuration file (/etc/nginx/conf.d/00_app_env.conf) during container boot. This file sets the passenger_app_env option in the http context. This means that if you already set passenger_app_env in the server context, running docker run -e PASSENGER_APP_ENV=... won't have any effect!

If you want to set a default value while still allowing that to be overridden by docker run -e PASSENGER_APP_ENV=, then instead of specifying passenger_app_env in your Nginx config file, you should create a /etc/nginx/conf.d/00_app_env.conf. This file will be overwritten if the user runs docker run -e PASSENGER_APP_ENV=....

# /etc/nginx/conf.d/00_app_env.conf
# File will be overwritten if user runs the container with `-e PASSENGER_APP_ENV=...`!
passenger_app_env staging;

Using Redis

Redis is only available in the passenger-customizable and passenger-full images!

Install and enable Redis:

# Opt-in for Redis if you're using the 'customizable' image.
#RUN /pd_build/redis.sh

# Enable the Redis service.
RUN rm -f /etc/service/redis/down

The configuration file is in /etc/redis/redis.conf. Modify it as you see fit, but make sure daemonize no is set.

Using memcached

Memcached is only available in the passenger-customizable and passenger-full images!

Install and enable memcached:

# Opt-in for Memcached if you're using the 'customizable' image.
#RUN /pd_build/memcached.sh

# Enable the memcached service.
RUN rm -f /etc/service/memcached/down

The configuration file is in /etc/memcached.conf. Note that it does not follow the Debian/Ubuntu format, but our own, in order to make it work well with runit. The default contents are:

# These arguments are passed to the memcached daemon.
MEMCACHED_OPTS="-l 127.0.0.1"

Additional daemons

You can add additional daemons to the image by creating runit entries. You only have to write a small shell script which runs your daemon, and runit will keep it up and running for you, restarting it when it crashes, etc.

The shell script must be called run, must be executable, and is to be placed in the directory /etc/service/<NAME>.

Here's an example showing you how to a memached server runit entry can be made.

### In memcached.sh (make sure this file is chmod +x):
#!/bin/sh
# `setuser` is part of baseimage-docker. `setuser mecached xxx...` runs the given command
# (`xxx...`) as the user `memcache`. If you omit this, the command will be run as root.
exec /sbin/setuser memcache /usr/bin/memcached >>/var/log/memcached.log 2>&1

### In Dockerfile:
RUN mkdir /etc/service/memcached
ADD memcached.sh /etc/service/memcached/run

Note that the shell script must run the daemon without letting it daemonize/fork it. Usually, daemons provide a command line flag or a config file option for that.

Tip: If you're thinking about running your web app, consider deploying it on Passenger instead of on runit. Passenger relieves you from even having to write a shell script, and adds all sorts of useful production features like process scaling, introspection, etc. These are not available when you're only using runit.

Using Ruby

We use RVM to install and to manage Ruby interpreters. Because of this there are some special considerations you need to know, particularly when you are using the passenger-full image which contains multiple Ruby versions installed in parallel. You can learn more about RVM at the RVM website, but this section will teach you its basic usage.

Selecting a default Ruby version

The default Ruby (what the /usr/bin/ruby command executes) is the latest Ruby version that you've chosen to install. You can use RVM select a different version as default.

# Ruby 3.1.6
RUN bash -lc 'rvm --default use ruby-3.1.6'
# Ruby 3.2.4
RUN bash -lc 'rvm --default use ruby-3.2.4'
# Ruby 3.3.3
RUN bash -lc 'rvm --default use ruby-3.3.3'
# JRuby 9.3.14.0
RUN bash -lc 'rvm --default use jruby-9.3.14.0'
# JRuby 9.4.6.0
RUN bash -lc 'rvm --default use jruby-9.4.6.0'

Learn more: RVM: Setting the default Ruby.

Running a command with a specific Ruby version

You can run any command with a specific Ruby version by prefixing it with rvm-exec <IDENTIFIER>. For example:

$ rvm-exec 3.1.6 ruby -v
Using /usr/local/rvm/gems/ruby-3.1.6
ruby 3.1.6p260 (2024-05-29 revision a777087be6) [x86_64-linux]

$ rvm-exec 3.3.3 ruby -v
Using /usr/local/rvm/gems/ruby-3.3.3
ruby 3.3.3 (2024-06-12 revision f1c7b6f435) [x86_64-linux]

More examples, but with Bundler instead:

# This runs 'bundle install' using Ruby 3.3.3
rvm-exec 3.3.3 bundle install

Default wrapper scripts

Rubies are installed by RVM to /usr/local/rvm. Interactive and login Bash shells load the RVM environment, which ensures that the appropriate directories under /usr/local/rvm are in PATH.

But this means that if you invoke a command without going through an interactive and login Bash shell (e.g. directly using docker exec) then the RVM environment won't be loaded. In order to make Ruby work even in this case, Passenger-docker includes a bunch of wrapper scripts:

  • /usr/bin/ruby
  • /usr/bin/rake
  • /usr/bin/gem
  • /usr/bin/bundle

These wrapper scripts execute the respective command through rvm-exec using the default Ruby interpreter.

Running scripts during container startup

passenger-docker uses the baseimage-docker init system, /sbin/my_init. This init system runs the following scripts during startup, in the following order:

  • All executable scripts in /etc/my_init.d, if this directory exists. The scripts are run during in lexicographic order.
  • The script /etc/rc.local, if this file exists.

All scripts must exit correctly, e.g. with exit code 0. If any script exits with a non-zero exit code, the booting will fail.

The following example shows how you can add a startup script. This script simply logs the time of boot to the file /tmp/boottime.txt.

### In logtime.sh (make sure this file is chmod +x):
#!/bin/sh
date > /tmp/boottime.txt

### In Dockerfile:
RUN mkdir -p /etc/my_init.d
ADD logtime.sh /etc/my_init.d/logtime.sh

Upgrading the operating system inside the container

passenger-docker images contain an Ubuntu 22.04 operating system. You may want to update this OS from time to time, for example to pull in the latest security updates. OpenSSL is a notorious example. Vulnerabilities are discovered in OpenSSL on a regular basis, so you should keep OpenSSL up-to-date as much as you can.

While we release passenger-docker images with the latest OS updates from time to time, you do not have to rely on us. You can update the OS inside passenger-docker images yourself, and it is recommend that you do this instead of waiting for us. This is also especially important to upgrade any installed Python or Node packages to the latest minor version.

To upgrade the OS in the image, run this in your Dockerfile:

RUN apt-get update && apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" upgrade

Upgrading Passenger to the latest version

Upgrading to the latest image

Passenger-docker images contain a specific Passenger version by default. We regularly update passenger-docker with the latest version of Passenger, Ruby, Node.js, etc.

To upgrade your image to the latest passenger-docker version, please edit your Dockerfile and change the passenger-docker version in the FROM command to the latest version. You can find a list of available versions in the Changelog.

For example, if you were using passenger-docker 0.9.16 and want to upgrade to 0.9.17, then change...

FROM phusion/passenger-docker-XXXX:0.9.16

...to:

FROM phusion/passenger-docker-XXXX:0.9.17

Then rebuild your image.

Upgrading Passenger without waiting for image updates

We do not update the passenger-docker image on every Passenger release. Having said that, you can upgrade Passenger at any time, without waiting for us to release a new image.

Passenger is installed through the Passenger APT repository, so you can use APT to upgrade Passenger.

To upgrade to the latest Passenger version, run this to your Dockerfile:

RUN apt-get update && apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" upgrade

Container administration

One of the ideas behind Docker is that containers should be stateless, easily restartable, and behave like a black box. However, you may occasionally encounter situations where you want to login to a container, or to run a command inside a container, for development, inspection and debugging purposes. This section describes how you can administer the container for those purposes.

Tip: passenger-docker is based on baseimage-docker. Please consult the baseimage-docker documentation for more container administration documentation and tips.

Running a one-shot command in a new container

Note: This section describes how to run a command insider a -new- container. To run a command inside an existing running container, see Running a command in an existing, running container.

Normally, when you want to create a new container in order to run a single command inside it, and immediately exit after the command exits, you invoke Docker like this:

docker run YOUR_IMAGE COMMAND ARGUMENTS...

However the downside of this approach is that the init system is not started. That is, while invoking COMMAND, important daemons such as cron and syslog are not running. Also, orphaned child processes are not properly reaped, because COMMAND is PID 1.

Passenger-docker provides a facility to run a single one-shot command, while solving all of the aforementioned problems. Run a single command in the following manner:

docker run YOUR_IMAGE /sbin/my_init -- COMMAND ARGUMENTS ...

This will perform the following:

  • Runs all system startup files, such as /etc/my_init.d/* and /etc/rc.local.
  • Starts all runit services.
  • Runs the specified command.
  • When the specified command exits, stops all runit services.

For example:

$ docker run phusion/passenger-full:<VERSION> /sbin/my_init -- ls
*** Running /etc/rc.local...
*** Booting runit daemon...
*** Runit started as PID 80
*** Running ls...
bin  boot  dev  etc  home  image  lib  lib64  media  mnt  opt  proc  root  run  sbin  selinux  srv  sys  tmp  usr  var
*** ls exited with exit code 0.
*** Shutting down runit daemon (PID 80)...
*** Killing all processes...

You may find that the default invocation is too noisy. Or perhaps you don't want to run the startup files. You can customize all this by passing arguments to my_init. Invoke docker run YOUR_IMAGE /sbin/my_init --help for more information.

The following example runs ls without running the startup files and with less messages, while running all runit services:

$ docker run phusion/passenger-full:<VERSION> /sbin/my_init --skip-startup-files --quiet -- ls
bin  boot  dev  etc  home  image  lib  lib64  media  mnt  opt  proc  root  run  sbin  selinux  srv  sys  tmp  usr  var

Running a command in an existing, running container

There are two ways to run a command inside an existing, running container.

Both way have their own pros and cons, which you can learn in their respective subsections.

Login to the container, or running a command inside it, via docker exec

You can use the docker exec tool on the Docker host OS to login to any container that is based on passenger-docker. You can also use it to run a command inside a running container. docker exec works by using Linux kernel system calls.

Here's how it compares to using SSH to login to the container or to run a command inside it:

  • Pros
    • Does not require running an SSH daemon inside the container.
    • Does not require setting up SSH keys.
    • Works on any container, even containers not based on passenger-docker.
  • Cons
    • If the docker exec process on the host is terminated by a signal (e.g. with the kill command or even with Ctrl-C), then the command that is executed by docker exec is not killed and cleaned up. You will either have to do that manually, or you have to run docker exec with -t -i.
    • Requires privileges on the Docker host to be able to access the Docker daemon. Note that anybody who can access the Docker daemon effectively has root access.
    • Not possible to allow users to login to the container without also letting them login to the Docker host.

Usage

Start a container:

docker run YOUR_IMAGE

Find out the ID of the container that you just ran:

docker ps

Now that you have the ID, you can use docker exec to run arbitrary commands in the container. For example, to run echo hello world:

docker exec YOUR-CONTAINER-ID echo hello world

To open a bash session inside the container, you must pass -t -i so that a terminal is available:

docker exec -t -i YOUR-CONTAINER-ID bash -l

Login to the container, or running a command inside it, via SSH

You can use SSH to login to any container that is based on passenger-docker. You can also use it to run a command inside a running container.

Here's how it compares to using docker exec to login to the container or to run a command inside it:

  • Pros
    • Does not require root privileges on the Docker host.
    • Allows you to let users login to the container, without letting them login to the Docker host. However, this is not enabled by default because passenger-docker does not expose the SSH server to the public Internet by default.
  • Cons
    • Requires setting up SSH keys. However, passenger-docker makes this easy for many cases through a pregenerated, insecure key. Read on to learn more.

Enabling SSH

Passenger-docker disables the SSH server by default. Add the following to your Dockerfile to enable it:

RUN rm -f /etc/service/sshd/down

# Regenerate SSH host keys. Passenger-docker does not contain any, so you
# have to do that yourself. You may also comment out this instruction; the
# init system will auto-generate one during boot.
RUN /etc/my_init.d/00_regen_ssh_host_keys.sh

About SSH keys

First, you must ensure that you have the right SSH keys installed inside the container. By default, no keys are installed, so nobody can login. For convenience reasons, we provide a pregenerated, insecure key (PuTTY format) that you can easily enable. However, please be aware that using this key is for convenience only. It does not provide any security because this key (both the public and the private side) is publicly available. In production environments, you should use your own keys.

Using the insecure key for one container only

You can temporarily enable the insecure key for one container only. This means that the insecure key is installed at container boot. If you docker stop and docker start the container, the insecure key will still be there, but if you use docker run to start a new container then that container will not contain the insecure key.

Start a container with --enable-insecure-key:

docker run YOUR_IMAGE /sbin/my_init --enable-insecure-key

Find out the ID of the container that you just ran:

docker ps

Once you have the ID, look for its IP address with:

docker inspect -f "{{ .NetworkSettings.IPAddress }}" <ID>

Now that you have the IP address, you can use SSH to login to the container, or to execute a command inside it:

# Download the insecure private key
curl -o insecure_key -fSL https://raw.githubusercontent.com/phusion/baseimage-docker/master/image/services/sshd/keys/insecure_key
chmod 600 insecure_key

# Login to the container
ssh -i insecure_key root@<IP address>

# Running a command inside the container
ssh -i insecure_key root@<IP address> echo hello world

Enabling the insecure key permanently

It is also possible to enable the insecure key in the image permanently. This is not generally recommended, but is suitable for e.g. temporary development or demo environments where security does not matter.

Edit your Dockerfile to install the insecure key permanently:

RUN /usr/sbin/enable_insecure_key

Instructions for logging in the container is the same as in section Using the insecure key for one container only.

Using your own key

Edit your Dockerfile to install an SSH public key:

## Install an SSH of your choice.
ADD your_key.pub /tmp/your_key.pub
RUN cat /tmp/your_key.pub >> /root/.ssh/authorized_keys && rm -f /tmp/your_key.pub

Then rebuild your image. Once you have that, start a container based on that image:

docker run your-image-name

Find out the ID of the container that you just ran:

docker ps

Once you have the ID, look for its IP address with:

docker inspect -f "{{ .NetworkSettings.IPAddress }}" <ID>

Now that you have the IP address, you can use SSH to login to the container, or to execute a command inside it:

# Login to the container
ssh -i /path-to/your_key root@<IP address>

# Running a command inside the container
ssh -i /path-to/your_key root@<IP address> echo hello world

The docker-ssh tool

Looking up the IP of a container and running an SSH command quickly becomes tedious. Luckily, we provide the docker-ssh tool which automates this process. This tool is to be run on the Docker host, not inside a Docker container.

First, install the tool on the Docker host:

curl --fail -L -O https://github.com/phusion/baseimage-docker/archive/master.tar.gz && \
tar xzf master.tar.gz && \
sudo ./baseimage-docker-master/install-tools.sh

Then run the tool as follows to login to a container using SSH:

docker-ssh YOUR-CONTAINER-ID

You can lookup YOUR-CONTAINER-ID by running docker ps.

By default, docker-ssh will open a Bash session. You can also tell it to run a command, and then exit:

docker-ssh YOUR-CONTAINER-ID echo hello world

Inspecting the status of your web app

If you use Passenger to deploy your web app, run:

passenger-status
passenger-memory-stats

Logs

If anything goes wrong, consult the log files in /var/log. The following log files are especially important:

  • /var/log/nginx/error.log
  • /var/log/syslog
  • Your app's log file in /home/app.

Switching to Phusion Passenger Enterprise

If you are a Phusion Passenger Enterprise customer, then you can switch to the Enterprise variant as follows.

  1. Login to the Customer Area.
  2. Download the license key and store it in the same directory as your Dockerfile.
  3. Insert into your Dockerfile:
ADD passenger-enterprise-license /etc/passenger-enterprise-license
RUN echo deb https://download:[email protected]/enterprise_apt $(lsb_release -cs) main > /etc/apt/sources.list.d/passenger.list
RUN apt-get update && apt-get install -y -o Dpkg::Options::="--force-confold" libnginx-mod-http-passenger-enterprise
Replace `$DOWNLOAD_TOKEN` with your actual download token, as found in the Customer Area.

Building the image yourself

If for whatever reason you want to build the image yourself instead of downloading it from the Docker registry, follow these instructions.

Clone this repository:

git clone https://github.com/phusion/passenger-docker.git
cd passenger-docker

Start a virtual machine with Docker in it. You can use the Vagrantfile that we've already provided.

vagrant up
vagrant ssh
cd /vagrant

Build one of the images:

make build_ruby31
make build_ruby32
make build_ruby33
make build_python38
make build_python39
make build_python310
make build_python311
make build_python312
make build_jruby93
make build_jruby94
make build_nodejs
make build_customizable
make build_full

If you want to call the resulting image something else, pass the NAME variable, like this:

NAME=joe/passenger make build_ruby32

Make will build images for both AMD64 and ARM64 by default. If you only want to build for one CPU architecture (ie. AMD64), disable the other architecture like this:

BUILD_ARM64=0 make build_ruby32

FAQ

Why are you using RVM? Why not rbenv or chruby?

In summary:

  • We have found RVM to be much more user friendly than rbenv and chruby.
  • RVM supplies precompiled binaries, while rbenv and chruby only support compiling Ruby from source.
  • Installing Ruby from Brightbox's APT repository caused too many problems. We used Brightbox's APT repository in the past, but we concluded that it is not the way to go forward.

Rbenv and chruby's main value proposition is that they are "simple". Indeed, they are simpler in implementation (fewer lines of code) than RVM, but they are not simpler to use. Rbenv and chruby are built on the Unix "do one thing only" philosophy. While this is sound, it is not necessarily the behavior that users want: I have seen many users struggling with basic rbenv/chruby usage because of lack of understanding of environment variables, or not having installed the right dependencies. Many users do not understand how the system is supposed to function and what all the different parts are, so doing one thing only may not be what they need. In such a case the simplicity ends up being more of a liability than an asset. It's like selling a car engine, frame and interior separately, while most consumers want an entire car.

RVM is built around a more "holistic" philosophy, if you will. It tries harder to be friendly to users who may not necessarily understand how everything works, for example by automatically installing a bash profile entry, by automatically installing necessary dependencies.

Another critique of RVM is that it is complicated and causes problems. This has not been our experience: perhaps this was the case in the past, but we have found RVM to be quite stable.

Why don't you just install Ruby manually from source?

By installing Ruby manually from source, we are just reinventing some of the functionality provided by a real Ruby version manager such as RVM, so we may as well use one to save ourselves time. There is no reason not to use RVM: it only occupies 5 MB of space.

Why are you not using the Brightbox's APT repository?

The Brightbox APT repository contains packages for multiple Ruby versions, which can be installed side-by-side. At first, this seems like the perfect solution. And indeed, passenger-docker used to use the Brightbox APT repository.

Unfortunately, we have found that it is much harder to make the different Rubies play nice with each other than it should be. Despite being installable side-to-side, they still conflict with each other. The most notable problem is that all Rubies' RubyGems install binwrappers to /usr/local/bin, but binwrappers generated by different Ruby versions may not be compatible with each other.

RVM provides much better isolation between different Ruby versions.

Why don't you just install Ruby from Ubuntu's APT repository?

Because we need to support Ruby versions not available from Ubuntu's APT repository. Besides, Ubuntu (and Debian) are notorious for being slow with updating Ruby packages. By the time the next Ruby version is released, we will have to wait until the next Ubuntu LTS version before we can use it.

Contributing

Thanks for your interest in contributing! There are many ways to contribute to this project. Get started here.

Conclusion

Please enjoy passenger-docker, a product by Phusion. :-)

passenger-docker's People

Contributors

af12066 avatar ajhodgson avatar arni-wxnc avatar baseballlover723 avatar bkmgit avatar camjn avatar dannytip avatar dependabot[bot] avatar floord avatar foobarwidget avatar gr8bit avatar juniorz avatar ledermann avatar nedaphilipp avatar neilbartley avatar odk211 avatar onixgh avatar paveg avatar pedros007 avatar perlun avatar rodrigobdz avatar scarhand avatar skunkworker avatar taleh007 avatar theaxiom avatar ties avatar tinco avatar tobischo avatar tsabat avatar yggdrasil avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

passenger-docker's Issues

authorized_keys in image

This doesn't seem right to me:

$ docker run -i -t phusion/passenger-ruby20 /bin/bash
root@ebd4c4b0d9c8:/# cat /home/app/.ssh/authorized_keys 
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDVmzBG5v7cO9IScGLIzlhGlHNFhXzy87VfaPzru7qnIIdQ1e9FEKvtqEws8hVixnCUdviwX5lvcMk4Ef4Tbrmj3dyF0zFtYbjiTSyl/XQlF68DQlc2sTAdHy96wJHvh7ky511tKJzzyWwSqeef4WjeVK28TqcGnq1up0S7saFO0dJh6OfDAg2cDmhyweR3VgT0vZJyrDV7hte95MBCdK+Gp7fdCyEZcWm3S1DBFaeBqHzzt/Y/njAVKbYL9TIVPum8iMg0rMiLi9ShfP+dT5Xud5Oa3dcN2OWhiDfJw5pfhFJWd44cJ/uGRwQpvNs/PNKsYABhgLlTMUH4iawhu1Xb hongli@asuna-3939

Why is there a hongli@asuna-3939 key in the authorized_keys of the app user?

Passenger Environment Variables

I'm trying to use passenger-docker to setup a Rails 4.1 app, and I think I'm having an issue surrounding passenger and environment variables. The issue I'm having is that when passenger starts up I get this error:

Could not find a JavaScript runtime. See https://github.com/sstephenson/execjs for a list of available runtimes. (ExecJS::RuntimeUnavailable)

Now I know that this error is not specific to passenger-docker, but I think that the reason it cannot find node.js is because of the PATH environment variable on the 'app' user. My asset pre-compilation works fine, so I know that node.js is there and execjs can use it.

I started to look around to see what the best way of getting the path to node.js into the PATH variable for the app user, and I'm not sure what the best way to go about this is. It doesn't seem like there are any hooks in nginx.conf that would allow me to use the 'env' command.

Maybe the path variable isn't the issue here, but based on the passenger error screen, it is set to this:

PATH = /home/app/client_harbor/vendor/bundle/ruby/2.1.0/bin

If you have other ideas I'd like to hear it. In the meantime though, is there a way to get environment variables to passenger that I'm missing?

passenger-full does not include redis

Hi,

I've noticed that even the passenger-full image doesn't actually have redis installed, though README.md seems to suggest that any but the minimal one does.

Should redis.sh be run when passenger-full is built? Happy to do a pull request if so.

Thanks,
George

separate https from http activity for squid-deb-proxy-client?

I have a fork of phusion/baseimage-docker where I've added in support for my own local squid-deb-proxy server, which speeds up rebuild of images immeasurably.

The phusion passenger mirror site is HTTPS-only and 302's the client if it tries to access any URL via un-crypted channels. I was trying to think of a way to deal with this and the best solution I can come up with is to do most of the work where proxy can be used (archive.ubuntu.com, ppa.launchpad.net) upfront, then add the HTTPS mirrors later and install the passenger debs only once the proxy has been disabled. Still this is not the best solution.

If this is too far out of scope feel free to close this issue with no action. I can't think of any good solution; maybe there is a way to instruct Apt to only use the proxy for HTTP plain text, it seems like The Internet Says that you have to explicitly enable the proxy for https, which I am not doing. http://chandrusoft.wordpress.com/2012/09/30/disable-proxy-when-using-apt-get/

I don't really want to MITM my connection with oss-binaries.phusionpassenger.com

How to configure nginx within passenger-docker to proxy to another container

Hey there,

I was wondering how I could get nginx inside the passenger container to proxy to a different container running on the same host. Specifically it would be a location directive e.g. /blog that I want to proxy. I'm just wondering how to get the IP address of the host dynamically and then insert that into the nginx conf.

Tag 0.9.11 not up on Docker registry

Changelog.md identified that a minor update, version 0.9.11, included a fix for an erroneous insecure key. Even though this update was made about a month ago, the new version tag is not available via the Docker registry.

Strange Error when installing postgres gem 'pg'

Hi there
I'm using the passenger-full image with version 0.9.11.
When trying to install the postgres gem (for ruby 2.1) I'm getting the following error:

Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

    /usr/bin/ruby2.1 extconf.rb 
checking for pg_config... no
No pg_config... trying anyway. If building fails, please try again with
 --with-pg-config=/path/to/pg_config
checking for libpq-fe.h... no
Can't find the 'libpq-fe.h header
*** extconf.rb failed ***

But I thought I saw the necessary lib "libpq-dev" as one of the install dependencies.

I get the same error when trying to use the ruby21 image.

Can you give me a hint what's wrong?

Container hangs on early shutdown

This is happening on an image which inherits from passenger-customizable:0.9.12, but I expect it's reproducible on baseimage.

If I kill a container while it's still starting, it completely hangs:

*** Running bash -l...
^C*** Shutting down bash (PID 10)...

*** Shutting down runit daemon (PID 9)...
ok: run: /etc/service/nginx-log-forwarder: (pid 27) 1s
*** runit daemon (PID 9) did not shut down in time. Forcing it to exit.
<stuck forever>

Split python support into 2.7 and 3.0

I am in a situation where I need only python 2.7, without python 3.0 and I would like to have the opportunity to install just one. As it is already possible with ruby

Upgraded to 0.9.12, image size shot up by 200 MB

Simply upgrading:

FROM phusion/passenger-ruby21:0.9.11
to
FROM phusion/passenger-ruby21:0.9.12

Increases the image size by 200 MB. If I docker-enter into the container, these two folders seem to have shot up in size:

/usr/share/doc
/usr/lib/x86_64-linux-gnu (mostly libqt stuff)

Any ideas what could have gone wrong?

References #52 - Might be related.

Code reloading in development mode?

Am I right in saying that passenger supports code reloading in development mode by setting the passenger_app_env to development?

I tried seeing passenger_app_env to development for a rails app running in a docker container but the code reload does not happen?

Am i missing a step?

thanks

chee

libqt should not be included as default

EDIT: Removed commit and image size reference, when we upgraded from 0.9.11 to 0.9.12 - our image size shot up by 200 MB, I'm trying to troubleshoot that separately. I thought it was because of libqt, but trying to confirm that

libqt seems to increase the image size by quite a bit. Specifically its this line:

## For capybara-webkit.
minimal_apt_get_install libqt4-webkit libqt4-dev

EDIT: Simple re-formatting and line breaks.

I think:

  • It kinda defeats the purpose of Docker to install pure Testing Dependencies (like capybara) by default to an image
  • Bundling testing dependencies is not recommended in general for Ruby/Rails production deployment
  • Developers have other ways to run tests (like Vagrant or something else), and in any case - this can be optionally installed by the Developers, not be included by default
  • This is highly targeting one narrow use case - capybara-webkit. Now why not install PhantomJS by default? Or selenium-webdriver (which is even more widely used)? webkit-gtk, firefox, xvfb, ... I think this decision of which testing framework to use is better taken by the developer
  • Finally, if I really wanted to do testing with capybara-webkit, I wouldn't really be using nginx/passenger and fiddling with deploying sites, will only be sticking with rack/unicorn/webrick as even cucumber/capybara defaults to

So in my mind, capybara-webkit and nginx/passenger are totally different use cases. Is it possible to fix this?

Add iojs alternative to nodejs images

With the release of iojs, node developers can get access to many of the promised 0.12 features, as well as a greatly updated v8. Would be great to have this in Phusion.

Alternatively, consider adding an NVM version, as nvm intends to have support "soon".

What does this line do?

Can someone please explain this line to me, how does it affect packages installation
It's in image / buildconfig

minimal_apt_get_install='apt-get install -y --no-install-recommends'

Adding Nginx Configure Option

I need to add a module to Nginx when running ./configure, specifically:

--add-module=/tmp/pagespeed/ngx_pagespeed-release-1.8.31.4-beta.

How do I go about doing so?

Thanks

Is it possible to remove the "App {PID} std{err|out}: " prefixes from logs?

It seems that by default Passenger prefixes logs with some information about what process/file descriptor the log came from. That makes sense, but in my particular use case I'd like to get rid of it.

Is there a flag/environment variable/whatever that I can use to just output the raw logs?

I realize this is really a Passenger thing, but I am using Passenger via Docker and figure this sort of concern might make more sense in a docker-specific environment. That said, let me know if it would be better to open an issue in phusion/passenger.

Missing build files in passenger-customizable

passenger-customizable:0.9.11 is missing two files, the absence of which bit me pretty hard.

/build/enable_repos.sh and
build/ruby_switch

I cloned the passenger_docker repo and just ADDed them manually as a workaround.

postgres

is there anything specific we need to bear in mind to install postgres? the ubuntu documentation asks to do a apt-get update, not sure if that will mess up with a docker container?

also after i install postgres its complaining about ports... is there a firewall for localhost from inside the machine?

Ruby minor version is not frozen in the container image

I just discovered that each time you build the image it will re install ruby (whatever major version) from the repository.

The problem is that if you specify in the Gemfile of your app a ruby version (for example 2.1.3) and then rebuild your docker container based on this image, the build process will build ruby 2.1 based on the latest minor version (2.1.4 today) which is different from the version of your Gemfile and your app will fail to start.

Bundle always uses Ruby 2.0

I'm no ruby expert, I just have to deploy Redmine, but when installing it, running bundle install ... installed gems for Ruby 2.0, regardless of which ruby version I selected.

After some investigation, the /usr/local/bin/bundle script explicitly used the /usr/bin/ruby2.0 executable...

Web application could not be started

Can anyone help me debug my issue? I've read the linked article but it hasn't helped.

An error occurred while starting up the preloader: it did not write a startup response in time. Please read this article for more information about this problem.
Raw process output:

 --> Compiling passenger_native_support.so for the current Ruby interpreter...
     (set PASSENGER_COMPILE_NATIVE_SUPPORT_BINARY=0 to disable)
     Warning: compilation didn't succeed. To learn why, read this file:
     /tmp/passenger_native_support-tco0f9.log
 --> Downloading precompiled passenger_native_support.so for the current Ruby interpreter...
     (set PASSENGER_DOWNLOAD_NATIVE_SUPPORT_BINARY=0 to disable)
     Could not download https://oss-binaries.phusionpassenger.com/binaries/passenger/by_release/4.0.40/rubyext-ruby-2.0.0-x86_64-linux-gnu.tar.gz: no download tool found (curl or wget required)
     Trying next mirror...
     Could not download https://s3.amazonaws.com/phusion-passenger/binaries/passenger/by_release/4.0.40/rubyext-ruby-2.0.0-x86_64-linux-gnu.tar.gz: no download tool found (curl or wget required)
 --> Continuing without passenger_native_support.so.
/usr/bin/env: ruby2.0: No such file or directory

Error output swallowed by my_init?

Failed commands run in a container return an error code, but the error output is being dropped.

Try running:

docker run --rm phusion/baseimage:0.9.13 /sbin/my_init -- fake_command

This will output:

<setup>
*** Running fake_command...
*** fake_command exited with status 127.
<cleanup>

Expected output:

bash: fake_command: command not found

Cannot find libruby.so.2.1

Since a couple days I'm getting this error:

libruby.so.2.1: cannot open shared object file: No such file or directory - /home/app/vendor/bundle/ruby/2.1.0/extensions/x86_64-linux/2.1.0/kgio-2.9.2/kgio_ext.so (LoadError)

my Dockerfile is this:

FROM phusion/passenger-ruby21

# Set correct environment variables.
ENV HOME /root

# Install vips
RUN apt-get update
RUN apt-get install -y libvips-dev

# Clean up APT when done
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

# Enable nginx and passenger
RUN rm -f /etc/service/nginx/down

# Setup app
ADD . /home/app
RUN chown -R app:app /home/app

WORKDIR /home/app
USER app
ENV HOME /home/app
RUN bundle install --without development:test --path vendor/bundle --binstubs vendor/bundle/bin --deployment --jobs 4 --retry 3
USER root

# Use baseimage-docker's init process.
CMD /sbin/my_init

I'm not sure I've changed something in the app, but it seems more a system level issue to me.

Error trying to install Ruby 2.0 as part of customizable

Using:

FROM phusion/passenger-customizable:0.9.11
RUN /build/utilities.sh
RUN /build/ruby2.0.sh

It's giving this error:

Step 4 : RUN /build/ruby2.0.sh
 ---> Running in ca6d54781bf6
+ apt-get install -y --no-install-recommends ruby2.0 ruby2.0-dev
Reading package lists...
Building dependency tree...
Reading state information...
Package ruby2.0 is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source

E: Package 'ruby2.0' has no installation candidate
E: Unable to locate package ruby2.0-dev
E: Couldn't find any package by regex 'ruby2.0-dev'

Any ideas? Thank you!

websockets support?

How do I upgrade nginx to use websockets with passenger apps if I'm not proxying to a standalone passenger instance?

Setting RAILS_ENV via Dockerfile or command line

Is it possible to set the RAILS_ENV during docker container startup? I want my Dockerfile / built container to work for every environment. But I don't know how to set it's RAILS_ENV to development. It always starts as production. Any ideas?

git repo pull example

would be good to have a working example of pulling in a git repo into the container via dockerfile. currently just doing it manually from inside the box and reimaging it instead of doing via dockerfile..

passenger-customizable is missing most scripts

I'm not really sure how to use it short of manually copying scripts such as enable_repos.sh. It doesn't seem to be well documented, nor does how to run passenger enterprise.

# ls build
buildconfig  devheaders.sh  nodejs.sh  redis.sh          ruby1.8.sh  ruby2.0.sh  runit
config       memcached.sh   python.sh  ruby-finalize.sh  ruby1.9.sh  ruby2.1.sh  utilities.sh

Precompile Ruby 2.0 extension

Hi there,

This seems like an interesting project - I was giving it a shot. However, every time I try to boot nginx/passenger, I get the following error:

Phusion Passenger: no passenger_native_support.so found for the current Ruby interpreter. Downloading precompiled binary from the Phusion server.......

This is just a one-file Sinatra app, so nothing complicated.

I'm doing the following in my Dockerfile

ADD app /home/app/webapp
RUN cd /home/app/webapp && gem install bundler && bundle install --without test development --deployment
RUN rm -f /etc/service/nginx/down

Any ideas?

Startup scripts run before Redis boots

I have several startup scripts, one of which requires redis. I've noticed that when the script runs during container startup, redis isn't available, but if I log into the container using docker-bash, it runs successfully.

Is it possible to run a script after redis has loaded?

How do I properly run nginx+meteor?

I'm not sure if I'm doing this correctly so pardon my ignorance.

I setup my Dockerfile like such:

FROM phusion/passenger-nodejs

# Set correct environment variables.
ENV HOME /root

# ssh
ADD private/keys/daniel.pub /tmp/your_key
RUN cat /tmp/your_key >> /root/.ssh/authorized_keys && rm -f /tmp/your_key

## Download shit
RUN apt-get update
RUN apt-get install -qq -y python-software-properties software-properties-common curl git build-essential

#setup meteor app
ADD .demeteorized /home/app/
WORKDIR /home/app/
RUN npm install
RUN mkdir public
RUN mkdir tmp
RUN chown -R app:app /home/app/

# Use baseimage-docker's init process.
CMD ["/sbin/my_init"]

# Enable nginx
ADD private/docker/vhost.conf /etc/nginx/sites-enabled/app.conf
ADD private/docker/env.conf /etc/nginx/main.d/meteor-env.conf
RUN rm -f /etc/nginx/sites-enabled/default
RUN rm -f /etc/service/nginx/down

# Clean up APT when done.
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

And I'm running it with:

› docker images
REPOSITORY                 TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
<none>                     <none>              59a8623e7e86        19 seconds ago      882.8 MB
 docker run -P 59a8623 /sbin/my_init
*** Running /etc/my_init.d/00_regen_ssh_host_keys.sh...
No SSH host key available. Generating one...
Creating SSH2 RSA key; this may take some time ...
Creating SSH2 DSA key; this may take some time ...
Creating SSH2 ECDSA key; this may take some time ...
Creating SSH2 ED25519 key; this may take some time ...
invoke-rc.d: policy-rc.d denied execution of restart.
*** Running /etc/rc.local...
*** Booting runit daemon...
*** Runit started as PID 97
ok: run: /etc/service/nginx-log-forwarder: (pid 115) 0s

And if I try to hit that url mapped from docker ps

 docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS                                           NAMES
a8ed3f90ad5e        59a8623e7e86        "/sbin/my_init"     About a minute ago   Up About a minute   0.0.0.0:49228->443/tcp, 0.0.0.0:49229->80/tcp   evil_fermi

Routes to: http://192.168.59.103:49229/

I get:

[ 2014-09-11 09:01:42.9768 116/7f7409d61780 agents/Watchdog/Main.cpp:538 ]: Options: { 'analytics_log_user' => 'nobody', 'default_group' => 'nogroup', 'default_python' => 'python', 'default_ruby' => '/usr/bin/ruby', 'default_user' => 'nobody', 'log_level' => '0', 'max_pool_size' => '6', 'passenger_root' => '/usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini', 'passenger_version' => '4.0.49', 'pool_idle_time' => '300', 'temp_dir' => '/tmp', 'union_station_gateway_address' => 'gateway.unionstationapp.com', 'union_station_gateway_port' => '443', 'user_switching' => 'true', 'web_server_passenger_version' => '4.0.49', 'web_server_pid' => '104', 'web_server_type' => 'nginx', 'web_server_worker_gid' => '33', 'web_server_worker_uid' => '33' }
[ 2014-09-11 09:01:42.9845 119/7f5cee1ac780 agents/HelperAgent/Main.cpp:650 ]: PassengerHelperAgent online, listening at unix:/tmp/passenger.1.0.104/generation-0/request
[ 2014-09-11 09:01:42.9943 124/7fa1da5517c0 agents/LoggingAgent/Main.cpp:321 ]: PassengerLoggingAgent online, listening at unix:/tmp/passenger.1.0.104/generation-0/logging
[ 2014-09-11 09:01:42.9947 116/7f7409d61780 agents/Watchdog/Main.cpp:728 ]: All Phusion Passenger agents started!
2014/09/11 09:02:28 [error] 134#0: *1 directory index of "/home/app/public/" is forbidden, client: 192.168.59.3, server: localhost, request: "GET / HTTP/1.1", host: "192.168.59.103:49229"
2014/09/11 09:02:28 [error] 134#0: *1 directory index of "/home/app/public/" is forbidden, client: 192.168.59.3, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "192.168.59.103:49229"
2014/09/11 09:02:29 [error] 134#0: *1 directory index of "/home/app/public/" is forbidden, client: 192.168.59.3, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "192.168.59.103:49229"
2014/09/11 09:02:29 [error] 134#0: *1 directory index of "/home/app/public/" is forbidden, client: 192.168.59.3, server: localhost, request: "GET / HTTP/1.1", host: "192.168.59.103:49229"
2014/09/11 09:02:29 [error] 134#0: *1 directory index of "/home/app/public/" is forbidden, client: 192.168.59.3, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "192.168.59.103:49229"
2014/09/11 09:02:29 [error] 134#0: *1 directory index of "/home/app/public/" is forbidden, client: 192.168.59.3, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "192.168.59.103:49229"
^C*** Shutting down runit daemon (PID 97)...
*** Killing all processes...

Why is it forbidden? Feels like it's not even starting the meteor app though.

I'm probably doing something very wrong here. I'm not sure how to start nginx enabled phusion with meteor.

I got it working standalone but used similar process except passenger start on the docker run instead of sbin/init.

Here's the vhost and env if interested:
https://gist.github.com/dfischer/2693b005c373ecdc1a92 vhost
https://gist.github.com/dfischer/8532bc9f26ce899fef6f env
Thanks.

Add Ruby 2.2

It would be great if Ruby 2.2 was added to the list of available ruby versions.

Nginx default site masks web app?

Trying to set up a webapp with the customizable image.

Had trouble getting nginx to serve requests to a Rails app. After poking around a bit in the image, it turns out that /etc/nginx/sites-enabled/default exists, and it takes over the catchall server name.

This bums me out when test-deploying images.

As soon as I removed the default site, nginx would merrily forward my requests to the rails app.

Is this intentional, or is it worth submitting a patch that clobbers the default site?

If it's worth noting, I'm currently not using Passenger as the rack server for the Rails app. I'd explore doing so after I get a stable build/deploy running, but right now Puma is working very well for us.

Services from /etc/service are not started automatically

Docker version 1.1.1
passenger-full:0.9.11

docker run --rm -t -i phusion/passenger-full bash -l
netstat -tulpn
top

no port is open, I have expected 22
no application is running apart of bash and top

After creating a Dockerfile with

RUN rm -f /etc/service/nginx/down
RUN rm -f /etc/service/redis/down
docker build -t user/rubystack .
docker run --name rubystack -d -t -i user/rubystack bash -l
docker attach rubystack
netstat -tulpn

no port is open, I have expected 22, 80 and 7474
no application is running apart of bash and top

Also, when I try to run nginx manually I get an error that /var/log/nginx/error.log is missing

/etc/service/nginx/run
warning: /etc/service/nginx-log-forwarder: unable to open supervise/ok: file does not exist

Howto install it for apache?

Is it possible to install it for apache2, too? With the "normal" passenger, I have the option for that and what must I do here?

How to set up vagrant + docker + nodejs + ruby + gems + apache + passenger?

synced folder don't have a correct user and group

in Vagrant file, i have below config:

v.vm.synced_folder ".", "/home/app/myproject", owner: 'app', group: 'app'

i expect the owner and group in the synced folder is app, but it is not:

root@7e50f7d51c5d:/home/app/myproject# pwd
/home/app/myproject
root@7e50f7d51c5d:/home/app/myproject# ls -l
total 96
-rw-rw-r-- 1 1000 docker_env  260 Jul 17 12:50 Berksfile
-rw-rw-r-- 1 1000 docker_env 2057 Jul 17 13:00 Gemfile
-rw-rw-r-- 1 1000 docker_env 5999 Jul 17 12:50 Gemfile.lock

Cannot get passed the couldn't install passenger support for the current Ruby interpreter

When using passenger-full, everything works fine until the container is running. I get the following error. Note that it is trying to download the rubyext-ruby-2.1.2 package, which doesn't exist, so it 404s.

Any ideas?

myapp_web_1 | ok: run: /etc/service/nginx-log-forwarder: (pid 114) 1s
myapp_web_1 | [ 2014-07-22 13:34:23.3721 115/7f2305556780 agents/Watchdog/Main.cpp:728 ]: All Phusion Passenger agents started!
myapp_web_1 | App 136 stdout: 
myapp_web_1 | App 136 stderr:  --> Compiling passenger_native_support.so for the current Ruby interpreter...
myapp_web_1 | App 136 stderr:      (set PASSENGER_COMPILE_NATIVE_SUPPORT_BINARY=0 to disable)
myapp_web_1 | App 136 stderr:  --> Downloading precompiled passenger_native_support.so for the current Ruby interpreter...
myapp_web_1 | App 136 stderr:      (set PASSENGER_DOWNLOAD_NATIVE_SUPPORT_BINARY=0 to disable)
myapp_web_1 | App 136 stderr:      Could not download https://oss-binaries.phusionpassenger.com/binaries/passenger/by_release/4.0.45/rubyext-ruby-2.1.2-x86_64-linux-gnu.tar.gz: The requested URL returned error: 404 Not Found
myapp_web_1 | App 136 stderr:      Trying next mirror...
myapp_web_1 | App 136 stderr:      Could not download https://s3.amazonaws.com/phusion-passenger/binaries/passenger/by_release/4.0.45/rubyext-ruby-2.1.2-x86_64-linux-gnu.tar.gz: The requested URL returned error: 403 Forbidden
myapp_web_1 | App 136 stderr:  --> Continuing without passenger_native_support.so.
myapp_web_1 | [ 2014-07-22 13:35:59.9421 118/7f4de0816700 Pool2/Implementation.cpp:883 ]: Could not spawn process for group /home/app/webapp#default: An error occurred while starting up the preloader: it did not write a startup response in time.
myapp_web_1 |      in 'void Passenger::ApplicationPool2::SmartSpawner::throwPreloaderSpawnException(const string&, Passenger::SpawnException::ErrorKind, Passenger::ApplicationPool2::Spawner::BackgroundIOCapturerPtr&, const DebugDirPtr&)' (SmartSpawner.h:142)
myapp_web_1 |      in 'std::string Passenger::ApplicationPool2::SmartSpawner::negotiatePreloaderStartup(Passenger::ApplicationPool2::SmartSpawner::StartupDetails&)' (SmartSpawner.h:562)
myapp_web_1 |      in 'void Passenger::ApplicationPool2::SmartSpawner::startPreloader()' (SmartSpawner.h:202)
myapp_web_1 |      in 'virtual Passenger::ApplicationPool2::ProcessPtr Passenger::ApplicationPool2::SmartSpawner::spawn(const Passenger::ApplicationPool2::Options&)' (SmartSpawner.h:746)
myapp_web_1 |      in 'void Passenger::ApplicationPool2::Group::spawnThreadRealMain(const SpawnerPtr&, const Passenger::ApplicationPool2::Options&, unsigned int)' (Implementation.cpp:804)
myapp_web_1 | 
myapp_web_1 | [ 2014-07-22 13:35:59.9424 118/7f4dde4db700 agents/HelperAgent/RequestHandler.h:2262 ]: [Client 20] Cannot checkout session.
myapp_web_1 | Error page:
myapp_web_1 | An error occurred while starting up the preloader: it did not write a startup response in time. Please read <a href="https://github.com/phusion/passenger/wiki/Debugging-application-startup-problems">this article</a> for more information about this problem.<br>
myapp_web_1 | <h2>Raw process output:</h2>
myapp_web_1 | <pre>
myapp_web_1 |  --&gt; Compiling passenger_native_support.so for the current Ruby interpreter...
myapp_web_1 |      (set PASSENGER_COMPILE_NATIVE_SUPPORT_BINARY=0 to disable)
myapp_web_1 |  --&gt; Downloading precompiled passenger_native_support.so for the current Ruby interpreter...
myapp_web_1 |      (set PASSENGER_DOWNLOAD_NATIVE_SUPPORT_BINARY=0 to disable)
myapp_web_1 |      Could not download https://oss-binaries.phusionpassenger.com/binaries/passenger/by_release/4.0.45/rubyext-ruby-2.1.2-x86_64-linux-gnu.tar.gz: The requested URL returned error: 404 Not Found
myapp_web_1 |      Trying next mirror...
myapp_web_1 |      Could not download https://s3.amazonaws.com/phusion-passenger/binaries/passenger/by_release/4.0.45/rubyext-ruby-2.1.2-x86_64-linux-gnu.tar.gz: The requested URL returned error: 403 Forbidden
myapp_web_1 |  --&gt; Continuing without passenger_native_support.so.
myapp_web_1 | </pre>
myapp_web_1 | [ 2014-07-22 13:35:59.9499 118/7f4dde4db700 agents/HelperAgent/RequestHandler.h:2262 ]: [Client 21] Cannot checkout session.
myapp_web_1 | Error page:
myapp_web_1 | An error occurred while starting up the preloader: it did not write a startup response in time. Please read <a href="https://github.com/phusion/passenger/wiki/Debugging-application-startup-problems">this article</a> for more information about this problem.<br>
myapp_web_1 | <h2>Raw process output:</h2>
myapp_web_1 | <pre>
myapp_web_1 |  --&gt; Compiling passenger_native_support.so for the current Ruby interpreter...
myapp_web_1 |      (set PASSENGER_COMPILE_NATIVE_SUPPORT_BINARY=0 to disable)
myapp_web_1 |  --&gt; Downloading precompiled passenger_native_support.so for the current Ruby interpreter...
myapp_web_1 |      (set PASSENGER_DOWNLOAD_NATIVE_SUPPORT_BINARY=0 to disable)
myapp_web_1 |      Could not download https://oss-binaries.phusionpassenger.com/binaries/passenger/by_release/4.0.45/rubyext-ruby-2.1.2-x86_64-linux-gnu.tar.gz: The requested URL returned error: 404 Not Found
myapp_web_1 |      Trying next mirror...
myapp_web_1 |      Could not download https://s3.amazonaws.com/phusion-passenger/binaries/passenger/by_release/4.0.45/rubyext-ruby-2.1.2-x86_64-linux-gnu.tar.gz: The requested URL returned error: 403 Forbidden
myapp_web_1 |  --&gt; Continuing without passenger_native_support.so.
myapp_web_1 | </pre>
myapp_web_1 | App 155 stdout: 
myapp_web_1 | App 155 stderr:  --> Compiling passenger_native_support.so for the current Ruby interpreter...
myapp_web_1 | App 155 stderr:      (set PASSENGER_COMPILE_NATIVE_SUPPORT_BINARY=0 to disable)
myapp_web_1 | App 155 stderr:  --> Downloading precompiled passenger_native_support.so for the current Ruby interpreter...
myapp_web_1 | App 155 stderr:      (set PASSENGER_DOWNLOAD_NATIVE_SUPPORT_BINARY=0 to disable)
myapp_web_1 | App 155 stderr:      Could not download https://oss-binaries.phusionpassenger.com/binaries/passenger/by_release/4.0.45/rubyext-ruby-2.1.2-x86_64-linux-gnu.tar.gz: The requested URL returned error: 404 Not Found
myapp_web_1 | App 155 stderr:      Trying next mirror...
myapp_web_1 | App 155 stderr:      Could not download https://s3.amazonaws.com/phusion-passenger/binaries/passenger/by_release/4.0.45/rubyext-ruby-2.1.2-x86_64-linux-gnu.tar.gz: The requested URL returned error: 403 Forbidden
myapp_web_1 | App 155 stderr:  --> Continuing without passenger_native_support.so.
myapp_web_1 | [ 2014-07-22 13:38:10.0399 118/7f4de0816700 Pool2/Implementation.cpp:883 ]: Could not spawn process for group /home/app/webapp#default: An error occurred while starting up the preloader: it did not write a startup response in time.
myapp_web_1 |      in 'void Passenger::ApplicationPool2::SmartSpawner::throwPreloaderSpawnException(const string&, Passenger::SpawnException::ErrorKind, Passenger::ApplicationPool2::Spawner::BackgroundIOCapturerPtr&, const DebugDirPtr&)' (SmartSpawner.h:142)
myapp_web_1 |      in 'std::string Passenger::ApplicationPool2::SmartSpawner::negotiatePreloaderStartup(Passenger::ApplicationPool2::SmartSpawner::StartupDetails&)' (SmartSpawner.h:562)
myapp_web_1 |      in 'void Passenger::ApplicationPool2::SmartSpawner::startPreloader()' (SmartSpawner.h:202)
myapp_web_1 |      in 'virtual Passenger::ApplicationPool2::ProcessPtr Passenger::ApplicationPool2::SmartSpawner::spawn(const Passenger::ApplicationPool2::Options&)' (SmartSpawner.h:746)
myapp_web_1 |      in 'void Passenger::ApplicationPool2::Group::spawnThreadRealMain(const SpawnerPtr&, const Passenger::ApplicationPool2::Options&, unsigned int)' (Implementation.cpp:804)
myapp_web_1 | 
myapp_web_1 | [ 2014-07-22 13:38:10.0403 118/7f4dde4db700 agents/HelperAgent/RequestHandler.h:2262 ]: [Client 20] Cannot checkout session.
myapp_web_1 | Error page:
myapp_web_1 | An error occurred while starting up the preloader: it did not write a startup response in time. Please read <a href="https://github.com/phusion/passenger/wiki/Debugging-application-startup-problems">this article</a> for more information about this problem.<br>
myapp_web_1 | <h2>Raw process output:</h2>
myapp_web_1 | <pre>
myapp_web_1 |  --&gt; Compiling passenger_native_support.so for the current Ruby interpreter...
myapp_web_1 |      (set PASSENGER_COMPILE_NATIVE_SUPPORT_BINARY=0 to disable)
myapp_web_1 |  --&gt; Downloading precompiled passenger_native_support.so for the current Ruby interpreter...
myapp_web_1 |      (set PASSENGER_DOWNLOAD_NATIVE_SUPPORT_BINARY=0 to disable)
myapp_web_1 |      Could not download https://oss-binaries.phusionpassenger.com/binaries/passenger/by_release/4.0.45/rubyext-ruby-2.1.2-x86_64-linux-gnu.tar.gz: The requested URL returned error: 404 Not Found
myapp_web_1 |      Trying next mirror...
myapp_web_1 |      Could not download https://s3.amazonaws.com/phusion-passenger/binaries/passenger/by_release/4.0.45/rubyext-ruby-2.1.2-x86_64-linux-gnu.tar.gz: The requested URL returned error: 403 Forbidden
myapp_web_1 |  --&gt; Continuing without passenger_native_support.so.
myapp_web_1 | </pre>

docker logs doesn't seem to capture my app's logs

Running docker logs doesn't seem to give me any useful log messages. I'd like to be able to see the output of console.log in my nodejs app but that doesn't seem to work out of the box. Any workarounds?

Installing Ruby with Rbenv fails due to potential memory problem

Hi there,

I am using this as my baseimage in my Vagrant provider. In this container, I am trying to install a ruby and consistently run into an issue that I believe is happening because of insufficient memory allocation to the compiler:

gcc: internal compiler error: Killed (program cc1)

Is there any way to increase the memory footprint of the virtual machine? (Am I even asking the right question? Perhaps this issue needs to be solved in another way.)

add to README: tip for running `/sbin/my_init` manually and debugging (from baseimage-docker README)

The baseimage-docker README makes it fairly clear that one can do things like the following, to debug when your /sbin/my_init is a dud (because you put bad scripts, etc.):

  • docker run --rm -t -i phusion/baseimage:<VERSION> /sbin/my_init -- bash -l (here)
  • docker run -t -i <YOUR_NAME_IMAGE> /sbin/my_init -- bash -l (here)

So in my use case, using passenger-docker base image and administering it with fig, I've learned I can do:

  • fig run web /sbin/my_init

to get at my problems in my web container. This is extremely helpful and before I realized I could do this, I was puzzled as to how to debug /sbin/my_init (because nothing winds up in syslog if you've completely borked it).

It will probably save some newbies (like me!) some trouble if the passenger-docker README also provides this suggestion for debugging.

Can't install passenger-docker

I'm now 3 days on it and it just not working...

I downloaded passenger-docker and put it in a folder. Than vagrant up with the dockerfile based in "image". Here my dockerfile:
http://pastie.org/9378190

After installing -> vagrant ssh -> cd /vagrant/images -> docker build -t justaname .

After all I got this:

docker images

REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
justaname latest a67f0905f540 8 seconds ago 735.7 MB
none none 624e0d224a70 2 minutes ago 661.9 MB
none none 47300eefb96f 24 hours ago 661.9 MB
phusion/passenger-full 0.9.11 5320fda0d529 2 weeks ago 732 MB
phusion/baseimage 0.9.11 dabfc8a40cb5 2 weeks ago 421.6 MB

Now I want "Adding your web app to the image", but the directory

/etc/nginx/sites-enabled/

is not there.

No nginx installed at all! Why? What goes wrong?

I really hope, you could help me.

Wrong/Missleading readme description - Setting nginx SECRET_KEY

You describe in the readme the setting of the nginx SECRET_KEY with:

env SECRET_KEY 123456;

and placing it in /etc/nginx/main.d/secret_key.conf

But this leads to the following error:

nginx: [emerg] invalid number of arguments in "env" directive in /etc/nginx/main.d/secret_key.conf:1

It might be a dump question but how CAN I set the secret key?

Regards

Cannot login as app user

Using the insecure_key works only for root, but it fails for app user:

ssh -i ~/.ssh/docker_passenger_insecure.key [email protected] -p 2222
Received disconnect from 127.0.0.1: 2: Too many authentication failures for app

In verbose mode I can see how it's trying to connect:

[ja:~/Projects/X] vagrant(+123/-89) 255 ± ssh -i ~/.ssh/docker_passenger_insecure.key [email protected] -p 2222 -v
OpenSSH_6.4, OpenSSL 1.0.1e-fips 11 Feb 2013
debug1: Reading configuration data /home/user/.ssh/config
debug1: /home/ja/.ssh/config line 1: Applying options for *
debug1: /home/ja/.ssh/config line 7: Applying options for 127.0.0.1
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 51: Applying options for *
debug1: auto-mux: Trying existing master
debug1: Control socket "/tmp/[email protected]:2222" does not exist
debug1: Connecting to 127.0.0.1 [127.0.0.1] port 2222.
debug1: Connection established.
debug1: identity file /home/ja/.ssh/docker_passenger_insecure.key type -1
debug1: identity file /home/ja/.ssh/docker_passenger_insecure.key-cert type -1
debug1: Enabling compatibility mode for protocol 2.0
debug1: Local version string SSH-2.0-OpenSSH_6.4
debug1: Remote protocol version 2.0, remote software version OpenSSH_6.6p1 Ubuntu-2ubuntu1
debug1: match: OpenSSH_6.6p1 Ubuntu-2ubuntu1 pat OpenSSH*
debug1: SSH2_MSG_KEXINIT sent
debug1: SSH2_MSG_KEXINIT received
debug1: kex: server->client aes128-ctr [email protected] none
debug1: kex: client->server aes128-ctr [email protected] none
debug1: sending SSH2_MSG_KEX_ECDH_INIT
debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
debug1: Server host key: ECDSA e3:e8:cf:11:3a:23:69:60:ff:b5:b5:d1:2f:83:b1:cb
debug1: Host '[127.0.0.1]:2222' is known and matches the ECDSA host key.
debug1: Found key in /home/ja/.ssh/known_hosts:59
debug1: ssh_ecdsa_verify: signature correct
debug1: SSH2_MSG_NEWKEYS sent
debug1: expecting SSH2_MSG_NEWKEYS
debug1: SSH2_MSG_NEWKEYS received
debug1: Roaming not allowed by server
debug1: SSH2_MSG_SERVICE_REQUEST sent
debug1: SSH2_MSG_SERVICE_ACCEPT received
debug1: Authentications that can continue: publickey,password
debug1: Next authentication method: publickey
[... 6 more keys trying ...]
debug1: Authentications that can continue: publickey,password
debug1: Trying private key: /home/user/.ssh/docker_passenger_insecure.key
debug1: read PEM private key done: type RSA
Received disconnect from 127.0.0.1: 2: Too many authentication failures for app

If I add -o 'IdentitiesOnly yes' it ask for a password

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.