Then we need to download instant client from oracle. This is complicated by Oracle insisting us to sign-in using OTN Account. Open your browser and point to "https://www.oracle.com/technetwork/database/database-technologies/instant-client/downloads/index.html", click on "Instant Client for Linux x86-64".

Click Accept License Agreement, then proceed to click the required rpm files (basic, devel, and sqlplus for 12.1.0.2 version). Do a dummy download using your browser (at this point Oracle would ask for your Oracle Account / OTN login, which we could request at no charge) and then copying the Link Address from browser, so we could use the Link Address URL in our wget commands.

The Url is obtainable from the Chrome's Downloads menu. Right click and choose 'Copy Link Address'.

Create another 'root' under the 'root' directory. Paste the URL between quotes to wget, and rename to take out AuthParam in the resulting file :

Step 3 : ENV SUMMARY "Platform for building and running PHP $PHP_VERSION applications" DESCRIPTION "PHP $PHP_VERSION available as docker container is a base platform for building and running various PHP $PHP_VERSION applications and frameworks. PHP is an HTML-embedded scripting language. PHP attempts to make it easy for developers to write dynamically generated web pages. PHP also offers built-in database integration for several commercial and non-commercial database management systems, so writing a database-enabled webpage with PHP is fairly simple. The most common use of PHP coding is probably as a replacement for CGI scripts."

This post shows the steps required to build your own Openshift Builder images. This might be needed when you need to connect to Oracle database using PDO extension, or there is additional command you want to be available in your application pods.
If you simply need additional extension that are readily available, there is an alternative simpler step involving the use of S2I assemble script (see http://inventorsparadox.blogspot.com/2018/04/installing-apcu-extension-in-openshift.html).
But if the extension need nontrivial dependencies, please read the remaining of this blog post.

Tools of the trade

We are going to need Docker toolset available. For Mac users, you could use Docker for Mac. For Windows users, there is Docker for Windows. I will show the screenshot from Docker running on CentOS Linux. You also going to need git (https://git-scm.com/download/win or https://git-scm.com/download/mac).

Build

Lets try to build the image :

aws@broker s2i-php-container $ cd 5.6

aws@broker 5.6 $ docker build -t s2i-php56-rfc .

Sending build context to Docker daemon

Post http:///var/run/docker.sock/v1.19/build?cgroupparent=&cpuperiod=0&cpuquota=0&cpusetcpus=&cpusetmems=&cpushares=0&dockerfile=Dockerfile&memory=0&memswap=0&rm=1&t=s2i-php56-rfc: dial unix /var/run/docker.sock: permission denied. Are you trying to connect to a TLS-enabled daemon without TLS?

Seems that the user needs permission to access docker. Check the permission:

aws@broker 5.6 $ ls -l /var/run/docker.sock

srw-rw----. 1 root root 0 Oct 232017 /var/run/docker.sock

It is owned by user root and group root. If you're using Centos, this should do the trick (run as root first):

Step 1 : EXPOSE 8080 ---> Using cache ---> da1f2520288f Step 2 : ENV PHP_VERSION 5.6 PATH $PATH:/opt/rh/rh-php56/root/usr/bin ---> Using cache ---> f944130c7708 Step 3 : ENV SUMMARY "Platform for building and running PHP $PHP_VERSION applications" DESCRIPTION "PHP $PHP_VERSION available as docker container is a base platform for building and running various PHP $PHP_VERSION applications and frameworks. PHP is an HTML-embedded scripting language. PHP attempts to make it easy for developers to write dynamically generated web pages. PHP also offers built-in database integration for several commercial and non-commercial database management systems, so writing a database-enabled webpage with PHP is fairly simple. The most common use of PHP coding is probably as a replacement for CGI scripts." ---> Using cache

...

Step 17 : USER 1001

---> Running in 0dca667bb85f

---> 199df5b9f228

Removing intermediate container 0dca667bb85f

Step 18 : CMD $STI_SCRIPTS_PATH/usage

---> Running in 922e0b45384a

---> 666d38e20eeb

Removing intermediate container 922e0b45384a

Successfully built 666d38e20eeb

So the build was a success, now we only need to publish to Docker Hub. It actually isn't a mandatory to publish to docker hub, but the alternative is to publish to Openshift Internal Registry which is not quite simple.

Publishing to Docker Hub

First examine that the image already built successfully :

aws@broker 5.6 $ docker images | grep s2i-php56-rfc

s2i-php56-rfclatest666d38e20eeb3 minutes ago 711.6 MB

Then retag the image (note: you should replace 'yudhiwidyatama' with you docker hub username):

This process takes a while, even hours if your upload internet connection is slow. Now you could see the image successfully uploaded to Docker Hub :

Conclusion

In this blog I have shown how to build a rfc-enabled PHP 5.6 S2I image using docker and upload the image to dockerhub.

The hard part

Actually I haven't discussed how to actually modify the docker image. The modification is in the lines 48-70 of the Dockerfile file.

The first three lines is to prepare directories that are we going to use in compiling the saprfc PHP extension :

RUN mkdir /opt/app-root/sap
RUN mkdir -p /usr/sap/rfcsdk
RUN mkdir /opt/app-root/saprfc-ext

The next two lines to add files from SAP's RFC SDK (extracted from file RFC_60-10003377.SAR from SAP Support) and PHP saprfc source code from http://saprfc.sourceforge.net/ :

ADD ./rfcsdk.tar.gz /usr/sap
ADD ./saprfc.tar.gz /opt/app-root

Note that the tar.gz file must be put in the same directory as the Dockerfile (check the github repo for resulting tar.gz).Afterwards, install PHP 5.6 development package with the required compatibility library.

Tuesday, April 10, 2018

Background

Openshift Origin is an open-source software developed by Red Hat, that aims to make operating Kubernetes cluster simpler. In Openshift, a base build docker image is used and merged with application source codes to create deployment docker images. Sometimes a software that we need doesn't get included in base build image, which will hamper Openshift adoption.

Base rules

These are a few facts related to docker images, that enables the approach in this blog post :

A. Linux binary from the same operating system release could be copied and used in another Linux OS. In this case we need to create a dummy image with the same OS version of the docker images and copy the relevant PHP extension binary from the image.

B. Some directories are writable during the build process, some are not. When running a build, we do not have full privileges, we are running under a pre-configured default user. When application pods are running it will be running under another configured user. Both user are unable to write to certain directories. Check by executing 'cat > filename' and 'touch filename' commands in Pod console.

C. Assemble script is going to be run during build time. We will add commands in this script in order to copy files from application source code to certain directories. Sometimes we need to experiment on the assemble script and checking the build logs for errors. Location of original assemble script might be different across platforms.

Initial Condition

For this blog article, we will be using standard Openshift Origin PHP 5.6 build image. Choose Add to Project, PHP, then PHP version 5.6.

Initially we don't have the APC extension in the resulting pods.

Target Condition

We are trying to run a PHP application using APCU extension, with phpinfo screen like this :

How-to

This is achieved by using these files in the application source code .sti/bin directory :

The key to enable extension installation is in the assemble script contents (which must be set to be executable, either locally by chmod u+x assemble or by git update-index ) :

#!/bin/bash

/usr/libexec/s2i/assemble

echo "Assembling.. "

CWD=`pwd`

echo "CWD = $CWD"

echo "short_open_tag=1" >> /etc/opt/rh/rh-php56/php.d/99-opentag.ini

cp .sti/bin/40-apcu.ini /etc/opt/rh/rh-php56/php.d/

ls -l /etc/opt/rh/rh-php56/php.d

The second line calls the original assemble script.

The sixth, create additional ini file for enabling PHP short open tag (which actually outside the context of this blog post). The seventh, copied apcu.ini file to the directory shown by phpinfo as "Scan this dir for additional .ini files".

The contents of apcu.ini actually altered to point to the extension file in the source directory:

; Enable APCu extension module

extension = /opt/app-root/src/.sti/bin/apcu.so

;This can be set to 0 to disable APCu

apc.enabled=1

... other content ..

Now, how do we obtain apcu.so ? My steps are a bit complicated, but for now thats all I have :

(note that you should install docker in your laptop first, create the .sti/bin folder, and change the some-directory to your internal path)

Sunday, December 10, 2017

The day I tried to install a Ruby gem for New Relic RPM, it causes almost a day downtime for Phusion Passenger-run Rails Application. It turns out that there are several thing that worth noting about Ruby dependency management.

The First Error

The error message that causes downtime is like this :

Ruby (Rack) application could not be started

These are the possible causes:

There may be a syntax error in the application's code. Please check for such errors and fix them.

A required library may not installed. Please install all libraries that this application requires.

The application may not be properly configured. Please check whether all configuration files are written correctly, fix any incorrect configurations, and restart this application.

A service that the application relies on (such as the database server or the Ferret search engine server) may not have been started. Please start that service.

Further information about the error may have been written to the application's log file. Please check it in order to analyse the problem.

Error message:

Could not find newrelic_rpm-3.18.1.330 in any of the sources (Bundler::GemNotFound)

Exception class:

PhusionPassenger::UnknownError

Application root:

/var/www/openshift/console

The nature of this error is tightly coupled to how 'bundle' and 'gem install' works.

Bundle install and Gem.lock

If we execute bundle install, bundle would :

1) connect to the internet to check for latest gem versions

2) Sometimes update the gem.lock (need to explore further when it does) when finding newer gem version

3) install the gem using standard gem environment

These 3 might break your application during some circumstances. In my case, the environment running the application is a bit different than the environment in the command line.

Gem environment

The result of running 'gem environment' tells much about the situation :

Things to note here, the INSTALLATION DIRECTORY and GEM PATHS difference. The /usr/local/share/gems exist in GEM PATHS, as well as /usr/share/gems, but INSTALLATION will put the gems under /usr/local/share/gems.

So the first GEM_PATH missed ruby193 prefix. Without the ruby193 prefix, the gems inside the actual directory would not be found, causing the error. Whats with the local directory anyway, this is not the first time I get confused by Linux/Unix directory scheme. It has historical significance but IMHO it is better not to have too many directories nowadays.

Solution to Problem I (or how to install newrelic_rpm in openshift broker&console)

Instead of fixing the GEM_PATH, I opt to use the install gem in the /usr/share/gems directory by using --install-dir :

Because version 0.9.2.2 is in available in the 'net (see https://rubygems.org/gems/rake/versions), I tried to use the internet by removing the --local keyword, and this time bundle complains about openshift-origin-console, which is not avaiable in the great internet.

The clue for the second error is the result of bundle config command :

broker console # bundle config

Settings are listed in order of priority. The top value will be used.

path

Set for your local app (/var/www/openshift/console/.bundle/config): "vendor"

disable_shared_gems

Set for your local app (/var/www/openshift/console/.bundle/config): "1"

Which is not the same with the neighboring application which has no settings at all:

broker broker # bundle config

Settings are listed in order of priority. The top value will be used.

broker broker #

Solution to problem II

The solution is to remove .bundle/config file, which inadvertently created when I tried running bundle install --path vendor. The file redirects local gem searches into the ./vendor directory, thus skipping /opt/rh/ruby193/root/usr/share/gems directory and causing the 2nd error. The bundle program are unable to find the openshift gem location because it were searching the ./vendor directory.

Lessons learned

What I learned, that is : bundle install are evil. It install new gems and change application dependencies, sometimes this breaks your app (especially if your app is written by Red Hat and has missed some GEM_PATH). You must understood bundle's basic mechanism, because incorrect parameters will lead to breaking your application.