Base docker healthcheck on STDOUT logs - ruby

I've got a script that outputs logs to STDOUT. I want to monitor this, and if x seconds passes without log output, the healthcheck should fail and the container should restart.
I've got something that I feel should work (using strace), but it's not. I'll post the files below. Does anyone have any idea how to solve this?
Dockerfile:
FROM ruby:2.5.1
RUN apt-get update
RUN dpkg --configure -a
ENV TZ=Europe/London
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y keyboard-configuration
RUN apt-get install -y --fix-missing curl gnupg build-essential mosh iceweasel git libappindicator1 postgresql libpq-dev xvfb xorg dbus-x11
RUN apt-get install -y --fix-missing libxss1 nodejs xfonts-100dpi xfonts-75dpi sqlite libindicator7 unzip wget curl bzip2 libssl-dev libreadline-dev zlib1g-dev strace
RUN ln -sf /usr/bin/nodejs /usr/local/bin/node
RUN gem install bundler activerecord activesupport watir watir-scroll nokogiri pg pry forgery rspec headless rake vcr webmock rails logger
WORKDIR /home/
COPY . .
HEALTHCHECK --interval=25s --timeout=5s --retries=5 CMD strace -p $(pgrep -n ruby) 2>&1 | grep -m 1 write\(
CMD ["ruby", "./test.rb"]
test.rb:
require 'logger'
$logger = Logger.new(STDOUT)
$logger.level = Logger::DEBUG
loop do
sleep 5
$logger.warn 'hi'
end
Logs are outputting as expected when running docker container log, but the health status is always starting, and shortly after starting it will consider it failed and restart. I intend to use Docker Swarm once this is working.

Related

gem command not found when install rbenv in debian

I'm creating a Dockerfile to run truffleruby. I'm getting an error when trying to install bundler and foreman. The error is /bin/sh: 1: gem: not found
Dockerfile
FROM debian:buster-slim
# Install packages for building ruby
RUN apt update -y && apt install -y git curl libssl-dev libpq-dev libreadline-dev zlib1g-dev \
autoconf bison build-essential libyaml-dev \
libreadline-dev libncurses5-dev libffi-dev libgdbm-dev
RUN apt clean
# Install rbenv and ruby-build
RUN git clone https://github.com/sstephenson/rbenv.git /root/.rbenv
RUN git clone https://github.com/sstephenson/ruby-build.git /root/.rbenv/plugins/ruby-build
RUN /root/.rbenv/plugins/ruby-build/install.sh
ENV PATH /root/.rbenv/bin:$PATH
RUN echo 'eval "$(rbenv init -)"' >> /etc/profile.d/rbenv.sh # or /etc/profile
RUN echo 'eval "$(rbenv init -)"' >> .bashrc
RUN . ~/.bashrc
RUN rbenv install truffleruby-20.3.0
RUN rbenv global truffleruby-20.3.0
RUN rbenv rehash
ENV BUNDLER_VERSION=2.2.4 NODE_ENV=production RAILS_ENV=production RAILS_SERVE_STATIC_FILES=true RAILS_LOG_TO_STDOUT=true PORT=3000
ENV CONFIGURE_OPTS --disable-install-doc
RUN apt-get install -y curl -sL https://deb.nodesource.com/setup_14.x | bash - && \
apt-get update && apt-get install -y nodejs && \
apt-get clean
RUN rbenv versions
RUN gem install bundler:2.2.4 foreman
RUN mkdir /app
WORKDIR /app
COPY Gemfile Gemfile.lock ./
RUN bundle config set --local deployment 'true'
RUN bundle config set --local without 'development test'
RUN bundle install
COPY . .
EXPOSE 3000
CMD ["foreman", "start"]
tail of build
Removing intermediate container 1a445fde7fc0
---> 43c3d72b7eb6
Step 17/27 : RUN rbenv versions
---> Running in feb5bb9361cc
* truffleruby-20.3.0 (set by /root/.rbenv/version)
Removing intermediate container feb5bb9361cc
---> c7d1a5826af5
Step 18/27 : RUN gem install bundler:2.2.4 foreman
---> Running in 998461afc89c
/bin/sh: 1: gem: not found
The command '/bin/sh -c gem install bundler:2.2.4 foreman' returned a non-zero code: 127
You don't generally use version managers like rbenv in Docker. There are a couple of reasons for this. One is that an image usually only contains a single application and its single runtime, so you'd never have more than one Ruby in an image and therefore there's no need to switch. A second is that most common paths of running containers (including docker run and the Dockerfile RUN directive) don't look at shell dotfiles like .bashrc or /etc/profile, so the version manager setup will never get run.
TruffleRuby is distributed (among other ways) as a standalone tar file so you can just install that in your Dockerfile. I'd make the Dockerfile look roughly like:
FROM debian:buster-slim
# Install the specific dependency packages TruffleRuby recommends
# (build-essential is much larger but might actually be necessary)
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive \
apt-get install --no-install-recommends --assume-yes \
curl \
gcc \
libssl-dev \
libz-dev \
make
# Download and unpack TruffleRuby
ARG TRUFFLERUBY_VERSION=20.3.0
ENV PATH /opt/truffleruby-$TRUFFLERUBY_VERSION-linux-amd64/bin:$PATH
RUN cd /opt \
&& curl -L https://github.com/oracle/truffleruby/releases/download/vm-$TRUFFLERUBY_VERSION/truffleruby-$TRUFFLERUBY_VERSION-linux-amd64.tar.gz | tar xz \
&& /opt/truffleruby-$TRUFFLERUBY_VERSION-linux-amd64/lib/truffle/post_install_hook.sh
# Now build and install your application
RUN gem install bundler:2.2.4
WORKDIR /app
COPY Gemfile Gemfile.lock ./
RUN bundle config set --local deployment 'true'
RUN bundle config set --local without 'development test'
RUN bundle install
COPY . .
ENTRYPOINT ["bundle", "exec"]
EXPOSE 3000
CMD ["rails", "start"]
You can reasonably split this into two separate Dockerfiles. End the first one before the "build and install your application" comment, and build it with docker build -t myname/truffleruby:20.3.0 -f Dockerfile.truffleruby .. Then the second one can begin with FROM myname/truffleruby:20.3.0 in the same way as the standard Docker Hub ruby image.
Does the same work with CRuby?
I'd suspect RUN doesn't read shell files, so PATH needs to be modified.
RUN git clone https://github.com/sstephenson/rbenv.git /root/.rbenv
...
RUN /root/.rbenv/plugins/ruby-build/install.sh
ENV PATH /root/.rbenv/bin:$PATH
seems a bit weird, is rbenv cloned and installed in the same place?
I would skip rbenv in Docker, and instead just:
RUN ruby-build truffleruby ~/.rubies/truffleruby
ENV PATH $HOME/.rubies/truffleruby/bin:$PATH

Docker - Ruby Dependencies installed at build time not available at container up

I am running the following command in my Dockerfile:
RUN apt-get update && apt-get -y install gnupg2
RUN gpg2 --keyserver hkp://keys.gnupg.net --recv-keys D39DC0E3
RUN curl -sSL https://get.rvm.io | bash -s
RUN /bin/bash -l -c ". /etc/profile.d/rvm.sh && rvm install 2.3.1 && rvm use --default 2.3.1 && gem install bundler"
# some more code
ENTRYPOINT ["/entrypoint.sh"]
In my entrypoint.sh, I am running bundle install. But it's throwing error:
bundle not found
Upon further investigation, I found that none of the dependencies installed during Docker build time seem to be available at container run time. I am probably missing something very basic. Help very appreciated.
The entrypoint.sh does not load rvm, so it doesn't see the rvm-installed Ruby or its bundler.
Load rvm in the entrypoint.sh by adding . /etc/profile.d/rvm.sh and rvm use .. before Ruby is used.

Docker container knows rbenv global but not ruby

When running my docker container it knows rbenv global. But when ever it try to find ruby via ruby or which ruby or whereis ruby I get nothing. It also doesn't recognize rails-api or gem. What is going on?
Dockerfile
FROM centos:6.6
RUN yum update -y
RUN yum install git openssl-devel openssh-server sudo openssl readline-devel readline zlib-devel zlib libxml2-devel libxml2 libxslt-devel libxslt nginx tar gcc libaio libaio-devel -y
RUN rpm -Uvh https://opscode-omnibus-packages.s3.amazonaws.com/el/6/x86_64/chef-12.5.1-1.el6.x86_64.rpm
RUN sed -i -e "s/Defaults requiretty.*/ #Defaults requiretty/g" /etc/sudoers
RUN mkdir -p /var/run/sshd
RUN useradd -m -u 1000 -G wheel deploy && echo '%wheel ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers.d/wheel
USER deploy
RUN mkdir ~/dev
RUN git clone https://github.com/sstephenson/rbenv.git ~/.rbenv/
RUN git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
ENV PATH ~/.rbenv/bin:$PATH
RUN echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
RUN source ~/.bash_profile
ENV CONFIGURE_OPTS --disable-install-doc
RUN rbenv install 2.2.3
RUN rbenv global 2.2.3
RUN bash -l -c 'gem update --system'
RUN bash -l -c 'gem update'
RUN bash -l -c 'gem install nokogiri -- --use-system-libraries'
RUN bash -l -c 'gem install bundler rails-api --no-rdoc --no-ri'
COPY oracle-instantclient12.1-basic-12.1.0.2.0-1.x86_64.rpm /tmp/oracle-instantclient12.1-basic-12.1.0.2.0-1.x86_64.rpm
COPY oracle-instantclient12.1-devel-12.1.0.2.0-1.x86_64.rpm /tmp/oracle-instantclient12.1-devel-12.1.0.2.0-1.x86_64.rpm
COPY oracle-instantclient12.1-sqlplus-12.1.0.2.0-1.x86_64.rpm /tmp/oracle-instantclient12.1-sqlplus-12.1.0.2.0-1.x86_64.rpm
RUN sudo rpm -Uvh /tmp/oracle-instantclient12.1-basic-12.1.0.2.0-1.x86_64.rpm
RUN sudo rpm -Uvh /tmp/oracle-instantclient12.1-devel-12.1.0.2.0-1.x86_64.rpm
RUN sudo rpm -Uvh /tmp/oracle-instantclient12.1-sqlplus-12.1.0.2.0-1.x86_64.rpm
RUN sudo touch /etc/sysconfig/network
RUN NLS_LANG=American_America.UTF8
ENV ORACLE_HOME=/usr/lib/oracle/12.1/client64
ENV LD_LIBRARY_PATH=/usr/lib/oracle/12.1/client64/lib
EXPOSE 22
EXPOSE 3000
EXPOSE 5000
The issue at hand here is that every RUN statement in the Dockerfile happens in its own environment. The RUN source ~/.bash_profile will set $PATH to have /root/.rbenv/shims in it. But subsequent RUN will not have this environment set as they won't source .bash_profile since this isn't an interactive shell.
The easy way to solve this is to just add a ENV PATH $HOME/.rbenv/bin:$HOME/.rbenv/shims:$PATH somewhere before the ruby and gem commands. This is really the only bit you should need from the rbenv init shell script.
Have you tried rbenv rehash after installing the new Ruby version?
Your Dockerfile only uses one version of Ruby. Given your use case, I would recommend just using the official ruby docker images: https://hub.docker.com/_/ruby

Installing Passenger & Nginx using Vagrant shell script

This is my first post to SO so I hope I'm asking this correctly.
I wrote a shell script to automate the installation of Passenger & Nginx (along with some other components) without any user input on a Vagrant VM running Ubuntu 14.04. It works fine using the following:
echo "****** Adding Passenger & Nginx Repo ******"
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 561F9B9CAC40B2F7
sudo apt-get install apt-transport-https ca-certificates -y
echo "deb https://oss-binaries.phusionpassenger.com/apt/passenger trusty main" | sudo tee /etc/apt/sources.list.d/passenger.list
sudo chown root: /etc/apt/sources.list.d/passenger.list
sudo chmod 600 /etc/apt/sources.list.d/passenger.list
sudo apt-get update
echo "****** Installing Passenger & Nginx ******"
sudo apt-get install nginx-extras passenger -y
Now I want to do the same thing for a Vagrant VM running CentOS 6.4. I followed the directions for CentOS found on the Phusion Passenger site but I can't seem to get it working properly. When I do the following, the output from the shell script says "No package passenger available.":
echo "****** Adding Passenger & Nginx Repo ******"
sudo yum install epel-release pygpgme curl -y
sudo 'echo "curl --fail -sSLo /etc/yum.repos.d/passenger.repo https://oss-binaries.phusionpassenger.com/yum/definitions/el-passenger.repo"'
sudo chown root: /etc/yum.repos.d/passenger.repo
sudo chmod 600 /etc/yum.repos.d/passenger.repo
sudo yum update
echo "****** Installing Passenger & Nginx ******"
sudo yum install nginx passenger -y
Looking in the /etc/yum.repos.d directory after the script is run, there is no passenger.repo listed, so it looks like for whatever reason curl is not downloading the repo file. However, if I manually type the commands in my terminal command line after the script finishes it will pull down the repo and run.
I'm probably doing something stupid here, but I'm rather new to shell scripting and can't seem to figure out where the problem is.
Thanks for any help you can give me.
sudo 'echo "curl --fail -sSLo /etc/yum.repos.d/passenger.repo https://oss-binaries.phusionpassenger.com/yum/definitions/el-passenger.repo"'
That is wrong and is not what the manual instructed. It should be:
sudo curl --fail -sSLo /etc/yum.repos.d/passenger.repo https://oss-binaries.phusionpassenger.com/yum/definitions/el-passenger.repo

Automate nginx installation via passenger

Every time we reinstall nginx using passenger, we have to provide to it a bunch of options to define the paths, modules and options we'd like to activate, which can be a bit of pain.
Does anybody know of a way to automate this using some kind of answer file?
Yes you can use a provisioning tool like Chef or Puppet but in some cases those can be overkill. I just have a Bash script with some variables at the top that get changed as necessary, I then just transfer the script to the target server and execute it.
The actual packages for nginx & passenger I keep in my own S3 bucket.
#!/bin/sh
# setup download location
DOWNLOAD_DIR=/tmp
NGINX="nginx-1.4.1"
NGINX_DIR=${DOWNLOAD_DIR}/${NGINX}
PASSENGER_VERSION="4.0.3"
S3HOST="your-s3-host"
# download nginx source
curl http://${S3HOST}.s3.amazonaws.com/software/${NGINX}.tar.gz -o $DOWNLOAD_DIR/${NGINX}.tar.gz
tar xzf $DOWNLOAD_DIR/${NGINX}.tar.gz --directory $DOWNLOAD_DIR
# download headers module
curl http://${S3HOST}.s3.amazonaws.com/software/headers-more-nginx-module-v0.16.zip -o $DOWNLOAD_DIR/headers-more-nginx-module-v0.16.zip
unzip $DOWNLOAD_DIR/headers-more-nginx-module-v0.16.zip -d $DOWNLOAD_DIR
# install passenger
apt-get install -y gcc g++ build-essential bison openssl libreadline6 lsof
apt-get install -y libreadline6-dev curl git-core zlib1g zlib1g-dev libssl-dev libpcre3-dev
apt-get install -y libyaml-dev libxml2-dev libxslt-dev autoconf libc6-dev ncurses-dev libcurl4-openssl-dev
apt-get install -y default-jre python-software-properties imagemagick
apt-get install -y ruby1.9.3 ruby1.9.1-dev libruby1.9.1 rubygems1.9.1 irb1.9.1 ri1.9.1 rdoc1.9.1 s3cmd
ln -nfs /var/lib/gems/1.9.1/bin/* /usr/bin/
gem install passenger -v ${PASSENGER_VERSION} --no-ri --no-rdoc
gem install bundler sass --no-ri --no-rdoc
# postgres client libraries
aptitude install software-properties-common -y
add-apt-repository -y ppa:pitti/postgresql
apt-get update
apt-get install -y postgresql-client-9.2 postgresql-server-dev-9.2
wget http://${S3HOST}.s3.amazonaws.com/software/passenger-enterprise-server-${PASSENGER_VERSION}.gem
gem install ./passenger-enterprise-server-${PASSENGER_VERSION}.gem --no-ri --no-rdoc
/var/lib/gems/1.9.1/gems/passenger-enterprise-server-${PASSENGER_VERSION}/bin/passenger-install-nginx-module \
--auto --prefix=/usr --nginx-source-dir=${NGINX_DIR} \
--extra-configure-flags="--conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --pid-path=/var/run/nginx.pid --http-client-body-temp-path=/var/tmp/nginx/client --http-proxy-temp-path=/var/tmp/nginx/proxy --http-fastcgi-temp-path=/var/tmp/nginx/fastcgi --with-md5-asm --with-md5=/usr/include --with-sha1-asm --with-sha1=/usr/include --without-http_fastcgi_module --with-http_stub_status_module --with-http_ssl_module --add-module=${DOWNLOAD_DIR}/headers-more-nginx-module-v0.16"
# make proper folders
mkdir -p /etc/nginx/sites-enabled
mkdir -p /etc/nginx/conf.d
mkdir -p /var/tmp/nginx
mkdir -p /etc/nginx/ssl/rapidssl
mkdir -p /var/www/shared/log/old_logs
chown -R vino:vino /var/www
# cleanup the stupid files
rm /etc/nginx/*.default
# start from init script
update-rc.d nginx defaults
# cleanup
rm -rf $DOWNLOAD_DIR/nginx*
passenger-install-apache2-module supports non-interactive, automatic, headless installs or upgrades through command line options. You can use those options to automate answers. This is documented in the manual: http://www.modrails.com/documentation/Users%20guide%20Nginx.html#_non_interactive_automatic_headless_installs_or_upgrades
Alternatively, you can install Phusion Passenger as if it's a normal Nginx module, and use the normal Nginx installation automation scripts: http://www.modrails.com/documentation/Users%20guide%20Nginx.html#_installing_as_a_normal_nginx_module_without_using_the_installer
You could use a provisioning tool such as chef or puppet. It may be overkill to use it for this case on its own, but you could use it to prepare entire servers or workstations from the ground up.

Resources