My new rails application won’t display the “Yay!” page!

I was doing some recent environment testing with rails with the same application created on each of OSX, CentOS, and Ubuntu and was surprised when the application gave an error about no root route available, instead of the “Yay!” page:


I, [2020-02-12T16:51:06.845723 #46720] INFO -- : [8d1ab83a-b4e4-45bf-a734-a6494c4d15c2] Started GET "/" for 127.0.0.1 at 2020-02-12 16:51:06 -0800
F, [2020-02-12T16:51:06.846251 #46720] FATAL -- : [8d1ab83a-b4e4-45bf-a734-a6494c4d15c2]
F, [2020-02-12T16:51:06.846316 #46720] FATAL -- : [8d1ab83a-b4e4-45bf-a734-a6494c4d15c2] ActionController::RoutingError (No route matches [GET] "/"):
F, [2020-02-12T16:51:06.846353 #46720] FATAL -- : [8d1ab83a-b4e4-45bf-a734-a6494c4d15c2]
F, [2020-02-12T16:51:06.846390 #46720] FATAL -- : [8d1ab83a-b4e4-45bf-a734-a6494c4d15c2] actionpack (5.2.4.1) lib/action_dispatch/middleware/debug_exceptions.rb:65:in `call'
[8d1ab83a-b4e4-45bf-a734-a6494c4d15c2] actionpack (5.2.4.1) lib/action_dispatch/middleware/show_exceptions.rb:33:in `call'
[8d1ab83a-b4e4-45bf-a734-a6494c4d15c2] railties (5.2.4.1) lib/rails/rack/logger.rb:38:in `call_app'
[8d1ab83a-b4e4-45bf-a734-a6494c4d15c2] railties (5.2.4.1) lib/rails/rack/logger.rb:26:in `block in call'
[8d1ab83a-b4e4-45bf-a734-a6494c4d15c2] activesupport (5.2.4.1) lib/active_support/tagged_logging.rb:71:in `block in tagged'
[8d1ab83a-b4e4-45bf-a734-a6494c4d15c2] activesupport (5.2.4.1) lib/active_support/tagged_logging.rb:28:in `tagged'
[8d1ab83a-b4e4-45bf-a734-a6494c4d15c2] activesupport (5.2.4.1) lib/active_support/tagged_logging.rb:71:in `tagged'
[8d1ab83a-b4e4-45bf-a734-a6494c4d15c2] railties (5.2.4.1) lib/rails/rack/logger.rb:26:in `call'
[8d1ab83a-b4e4-45bf-a734-a6494c4d15c2] actionpack (5.2.4.1) lib/action_dispatch/middleware/remote_ip.rb:81:in `call'
[8d1ab83a-b4e4-45bf-a734-a6494c4d15c2] actionpack (5.2.4.1) lib/action_dispatch/middleware/request_id.rb:27:in `call'
[8d1ab83a-b4e4-45bf-a734-a6494c4d15c2] rack (2.2.2) lib/rack/method_override.rb:24:in `call'
[8d1ab83a-b4e4-45bf-a734-a6494c4d15c2] rack (2.2.2) lib/rack/runtime.rb:22:in `call'
[8d1ab83a-b4e4-45bf-a734-a6494c4d15c2] activesupport (5.2.4.1) lib/active_support/cache/strategy/local_cache_middleware.rb:29:in `call'
[8d1ab83a-b4e4-45bf-a734-a6494c4d15c2] actionpack (5.2.4.1) lib/action_dispatch/middleware/executor.rb:14:in `call'
[8d1ab83a-b4e4-45bf-a734-a6494c4d15c2] rack (2.2.2) lib/rack/sendfile.rb:110:in `call'
[8d1ab83a-b4e4-45bf-a734-a6494c4d15c2] railties (5.2.4.1) lib/rails/engine.rb:524:in `call'
[8d1ab83a-b4e4-45bf-a734-a6494c4d15c2] puma (3.12.2) lib/puma/configuration.rb:227:in `call'
[8d1ab83a-b4e4-45bf-a734-a6494c4d15c2] puma (3.12.2) lib/puma/server.rb:674:in `handle_request'
[8d1ab83a-b4e4-45bf-a734-a6494c4d15c2] puma (3.12.2) lib/puma/server.rb:476:in `process_client'
[8d1ab83a-b4e4-45bf-a734-a6494c4d15c2] puma (3.12.2) lib/puma/server.rb:334:in `block in run'
[8d1ab83a-b4e4-45bf-a734-a6494c4d15c2] puma (3.12.2) lib/puma/thread_pool.rb:135:in `block in spawn_thread'

I had assumed that any new rails application would serve out the, every so happy, “Yay!” page, regardless of environment. It turns out not to be the case. To fix the issue, set the RAILS_ENV to development and restart the rails server:


> RAILS_ENV=development rails server
=> Booting Puma
=> Rails 5.2.4.1 application starting in development
=> Run `rails server -h` for more startup options
Puma starting in single mode...
* Version 3.12.2 (ruby 2.6.0-p0), codename: Llamas in Pajamas
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://localhost:3000
Use Ctrl-C to stop

Easy fix!

Rails new fails to create all of the content…

I recently deployed a Rails app on a CentOS 8 container and was surprised to see that the ‘rails new’ command did not create the entire application directory structure that I would expect, ie:

[root@607ebc931c48 app]# rails _5.2.3_ new centos_app_2
      create
      create  README.md
      create  Rakefile
      create  .ruby-version
      create  config.ru
      create  .gitignore
      create  Gemfile
         run  git init from "."

I didn’t know that git was a requirement now for rails apps, so the issue was resolved by installing the git client.

# dnf install -y git

To get a rails application created using a CentOS 8 docker container, use the following steps. This will assume rails 5.2.3 and ruby 2.6.3:

docker run -i -t --rm -v ${PWD}:/usr/src/app centos:8 bash
dnf install curl git gnupg2 which -y
gpg2 --keyserver hkp://pool.sks-keyservers.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
curl -sSL https://get.rvm.io | bash -s stable
source /etc/profile.d/rvm.sh
rvm requirements
rvm install 2.6.3
gem install rails -v 5.2.3
rails _5.2.3_ new centos_app

Note that the container actually takes quite a bit to build, so making an image would be more useful as subsequent rails commands could be run more easily.

Running Apache 2 under Ubuntu 16.04 on Docker

I recently wanted to setup a new Ubuntu 16.04 host running Apache under Docker for some AWS ECS/Fargate testing I was doing and encountered the following error:

docker run -p 8085:80 aws-ecr-hello-world:v0.5
[Thu Mar 15 00:11:31.074011 2018] [core:warn] [pid 1] AH00111: Config variable ${APACHE_LOCK_DIR} is not defined
[Thu Mar 15 00:11:31.074576 2018] [core:warn] [pid 1] AH00111: Config variable ${APACHE_PID_FILE} is not defined
AH00526: Syntax error on line 74 of /etc/apache2/apache2.conf:
Invalid Mutex directory in argument file:${APACHE_LOCK_DIR}

This is a typical Ubuntu problem where the /etc/apache2/envvars file needs to be sourced before apache2 can start properly. To figure out which ones needed to be added, I commented out the CMD to start apache and instead entered a command to print out the contents of the envvars file. I also added a sed command to print out line 74 of the apache2.conf file so I could further troubleshoot what was happening there.

# Dockerfile
...
CMD ["cat", "/etc/apache2/envvars"]
CMD ["sed", "-n", "74p", "/etc/apache2/apache2.conf"]
...

This output showed that I had to add a few environment variables to the Dockerfile, and verify that they exist when I run the container:

# Dockerfile
...
ENV APACHE_RUN_USER  www-data
ENV APACHE_RUN_GROUP www-data
ENV APACHE_LOG_DIR   /var/log/apache2
ENV APACHE_PID_FILE  /var/run/apache2/apache2.pid
ENV APACHE_RUN_DIR   /var/run/apache2
ENV APACHE_LOCK_DIR  /var/lock/apache2
ENV APACHE_LOG_DIR   /var/log/apache2

RUN mkdir -p $APACHE_RUN_DIR
RUN mkdir -p $APACHE_LOCK_DIR
RUN mkdir -p $APACHE_LOG_DIR
...

I also verified that the directories would exist to prevent any issues there:

# Dockerfile
...
RUN mkdir -p $APACHE_RUN_DIR
RUN mkdir -p $APACHE_LOCK_DIR
RUN mkdir -p $APACHE_LOG_DIR
...

After I finished that, I rebuilt the image and was able to run the container without issues.

The full Dockerfile is:

FROM ubuntu:16.04

# Install dependencies
RUN apt-get update -y
RUN apt-get install -y apache2

# Install apache and write hello world message
RUN echo "Hello World!" > /var/www/index.html

# Configure apache
RUN a2enmod rewrite
RUN chown -R www-data:www-data /var/www


ENV APACHE_RUN_USER  www-data
ENV APACHE_RUN_GROUP www-data
ENV APACHE_LOG_DIR   /var/log/apache2
ENV APACHE_PID_FILE  /var/run/apache2/apache2.pid
ENV APACHE_RUN_DIR   /var/run/apache2
ENV APACHE_LOCK_DIR  /var/lock/apache2
ENV APACHE_LOG_DIR   /var/log/apache2

RUN mkdir -p $APACHE_RUN_DIR
RUN mkdir -p $APACHE_LOCK_DIR
RUN mkdir -p $APACHE_LOG_DIR

EXPOSE 80

# CMD ["sed", "-n", "74p", "/etc/apache2/apache2.conf"]
# CMD ["cat", "/etc/apache2/envvars"]
 CMD ["/usr/sbin/apache2", "-D",  "FOREGROUND"]

Build the container image:

> docker build -t aws-ecr-hello-world:v0.9.1 .
Sending build context to Docker daemon   2.56kB
Step 1/18 : FROM ubuntu:16.04
 ---> f975c5035748
Step 2/18 : RUN apt-get update -y
 ---> Using cache
 ---> 1716ac62d2f6
Step 3/18 : RUN apt-get install -y apache2
 ---> Using cache
 ---> b03c08c103b5
Step 4/18 : RUN echo "Hello World!" > /var/www/index.html
 ---> Using cache
 ---> a8352375b937
Step 5/18 : RUN a2enmod rewrite
 ---> Using cache
 ---> 313f2e8046ec
Step 6/18 : RUN chown -R www-data:www-data /var/www
 ---> Using cache
 ---> c2e7512d4fe8
Step 7/18 : ENV APACHE_RUN_USER  www-data
 ---> Using cache
 ---> 2054c48681ae
Step 8/18 : ENV APACHE_RUN_GROUP www-data
 ---> Using cache
 ---> 493b20667534
Step 9/18 : ENV APACHE_LOG_DIR   /var/log/apache2
 ---> Using cache
 ---> 8c5029eb8e83
Step 10/18 : ENV APACHE_PID_FILE  /var/run/apache2/apache2.pid
 ---> Using cache
 ---> 701ddcccf335
Step 11/18 : ENV APACHE_RUN_DIR   /var/run/apache2
 ---> Using cache
 ---> 6700b8a02ca0
Step 12/18 : ENV APACHE_LOCK_DIR  /var/lock/apache2
 ---> Using cache
 ---> ac692e86caf7
Step 13/18 : ENV APACHE_LOG_DIR   /var/log/apache2
 ---> Using cache
 ---> 660af37232bc
Step 14/18 : RUN mkdir -p $APACHE_RUN_DIR
 ---> Running in 02978786f1b5
Removing intermediate container 02978786f1b5
 ---> 3e5ef0c00431
Step 15/18 : RUN mkdir -p $APACHE_LOCK_DIR
 ---> Running in 68408f3091c1
Removing intermediate container 68408f3091c1
 ---> 90efa3a2f9bc
Step 16/18 : RUN mkdir -p $APACHE_LOG_DIR
 ---> Running in f1ee7e4d5a4b
Removing intermediate container f1ee7e4d5a4b
 ---> 9fb6a50c6792
Step 17/18 : EXPOSE 80
 ---> Running in f3fd904326e4
Removing intermediate container f3fd904326e4
 ---> b4ba8575620d
Step 18/18 : CMD ["/usr/sbin/apache2", "-D",  "FOREGROUND"]
 ---> Running in a3cba653d7b3
Removing intermediate container a3cba653d7b3
 ---> 0bfa187abf69
Successfully built 0bfa187abf69
Successfully tagged aws-ecr-hello-world:v0.9.1

Run the container:

> docker run -p 8085:80 aws-ecr-hello-world:v0.9.1
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message

UPDATE: it looks like James Turnbull had already solved this problem here.

docker run docs confusing – which port?

I was reviewing the docker docs today in an attempt to get things working on OSX and ran into a conflict when starting a new container running nginx. The docs say to run the following command:

> docker run -d -p 80:80 --name webserver nginx

That seems pretty straight forward, so I ran the command:

> docker run -d -p 80:80 --name webserver nginx
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
94ed0c431eb5: Pull complete
9406c100a1c3: Pull complete
aa74daafd50c: Pull complete
Digest: sha256:788fa27763db6d69ad3444e8ba72f947df9e7e163bad7c1f5614f8fd27a311c3
Status: Downloaded newer image for nginx:latest
900f5e2ff097677bd6af8825cd0f0f6961b462714528d75245e73841d0f4f30c
docker: Error response from daemon: driver failed programming external connectivity on endpoint webserver (4fa9e84616ebb7c7aa86a345a4caa01910d8fdcb00b71d0bd8daf6b9443a0a7a): Error starting userland proxy: Bind for 0.0.0.0:80: unexpected error (Failure EADDRINUSE).

After getting this error, I see that I have something listening on port 80 already, that’s no problem. The logical thing to do would be to refer to the docs real quick to figure out which side of the colon mapped to the port on the container and which side mapped to the port on my OSX host. I could not find an explanation for this in the docker docs. I did a bit of searching around as well, with no luck. I don’t see this documented.

The next logical step, or more likely the first, was to just try them both and see which one worked. The left side is the docker host and the right side is the container, ie:

> docker run  -d -p 3060:80 --name webserver3060 nginx
b2605b247f405a74761e042ed089e966995bfcce6b8268696410314ac6984965

I was then able to successful query the service on port 3060 by using curl or using my browser at http://localhost:3060/.