Table of Contents generated with DocToc
Quickstarts are great, but sometimes a developer wants to build up the various components manually. Let's take our quickstart example and treat it like two separate "applications" that we want to wire together.
Open a terminal as alice
:
# su - alice
Then, create a project for this example:
oc new-project wiring --display-name="Exploring Parameters" \
--description='An exploration of wiring using parameters'
Log into the web console as alice
. Can you see joe
's projects and content?
Before continuing, alice
will also need the training repository:
cd
git clone https://github.com/openshift/training.git
cd ~/training/content
The first step will be to stand up the frontend of our application. For argument's sake, this could have just as easily been brand new vanilla code. However, to make things faster, we'll start with an application that already is looking for a DB, but won't fail spectacularly if one isn't found.
The frontend application comes from the following code repository:
https://github.com/openshift/ruby-hello-world
We want to use the beta branch. We can use the new-app
command to help get
this started for us. As alice
go ahead and do the following:
oc new-app -i openshift/ruby https://github.com/openshift/ruby-hello-world
You should see something like the following:
I0728 14:27:23.047056 8906 newapp.go:301] Image "openshift/ruby" is a builder, so a repository will be expected unless you also specify --strategy=docker
I0728 14:27:23.047163 8906 newapp.go:337] Using "https://github.com/openshift/ruby-hello-world#beta4" as the source for build
imagestreams/ruby-hello-world
buildconfigs/ruby-hello-world
deploymentconfigs/ruby-hello-world
services/ruby-hello-world
A build was created - you can run `oc start-build ruby-hello-world` to start it.
Service "ruby-hello-world" created at 172.30.103.182 with port mappings 8080.
The syntax of the command tells us:
- I want to create a new application
- using the ruby builder image in the openshift project
- based off of the code in a git repository
Since we know that we want to talk to a database eventually, let's take a moment
to add the environment variables for it. Conveniently, there is an env
subcommand to oc
. As alice
, we can use it like so:
oc env dc/ruby-hello-world MYSQL_USER=root MYSQL_PASSWORD=redhat MYSQL_DATABASE=mydb
If you want to double-check, you can verify using the following:
oc env dc/ruby-hello-world --list
# deploymentconfigs ruby-hello-world, container ruby-hello-world
MYSQL_USER=root
MYSQL_PASSWORD=redhat
MYSQL_DATABASE=mydb
At this point, you probably have a build running and a second deployment. That second deployment is because we've changed the configuration of the deployment, which results in a new deployment.
For example, oc get pod
might look like:
NAME READY REASON RESTARTS AGE
ruby-hello-world-1-build 1/1 Running 0 1m
ruby-hello-world-2-3jby9 0/1 Error: image library/ruby-hello-world:latest not found 0 32s
Wait for the build to complete, and you should end up with a running front-end in a few moments. You'll probably end up with something like this:
oc get pod
NAME READY REASON RESTARTS AGE
ruby-hello-world-1-build 0/1 ExitCode:0 0 7m
ruby-hello-world-3-eq9w3 1/1 Running 0 5m
While it won't look great using curl
, we can validate the frontend is running
with it. The previous steps should have resulted in a service being created:
oc get service
NAME LABELS SELECTOR IP(S) PORT(S)
ruby-hello-world <none> deploymentconfig=ruby-hello-world 172.30.103.182 8080/TCP
We can hit that with curl
:
curl -s `oc get service | grep world | awk '{print $4":"$5}' | sed -e 's/\/.*//'` | grep database
<h3>(It looks like the database isn't running. This isn't going to be much fun.)</h3>
This is good so far!
The oc
command has a nifty subcommand called expose
that will take a service
and automatically create a route for us. It will do this in the defined cloud
domain and in the current project as an additional "namespace" of sorts. For
example, the steps above resulted in a service called "ruby-hello-world". We can
use expose
against it:
oc expose service ruby-hello-world
After a few moments:
oc get route
NAME HOST/PORT PATH SERVICE LABELS
ruby-hello-world ruby-hello-world.wiring.cloudapps.example.com ruby-hello-world
Remember, the host
was automatically generated from the service name and the
project name. oc expose
also takes a --hostname
argument if you need to use
something specific.
Now you should be able to access your application with your browser! Go ahead and do that now. You'll notice that the frontend is happy to run without a database, but is not all that exciting. We'll fix that in a moment.
During the installation, several templates were added for us, including some
database templates. Go to the web console and make sure you are logged in as
alice
and using the Exploring Parameters
project. You should see your
front-end already there. Click the "Create..." button and then the "Browse all
templates..." button. You should see the mysql-ephemeral
template. Click it
and then click "Select template".
You will need to edit the parameters of this template, because the defaults will
not work for us. Change the DATABASE_SERVICE_NAME
to be "database", because
that is what service the frontend expects to connect to. Make sure that the
MySQL user, password and database match whatever values you specified in the
previous labs.
Click the "Create" button when you are ready.
It may take a little while for the MySQL container to download (if you didn't pre-fetch it). It's a good idea to verify that the database is running before continuing. If you don't happen to have a MySQL client installed you can still verify MySQL is running with curl:
curl `oc get services | grep database | awk '{print $4}'`:3306
MySQL doesn't speak HTTP so you will see garbled output like this (however, you'll know your database is running!):
5.6.2K\l-7mA<��F/T:emsy'TR~mysql_native_password!��#08S01Got packets out of order
Visit your application again with your web browser. Why does it still say that there is no database?
When the frontend was first built and created, there was no service called
"database", so the environment variable DATABASE_SERVICE_HOST
did not get
populated with any values. Our database does exist now, and there is a service
for it, but OpenShift could not "inject" those values into the running frontend
container.
The easiest way to get this going? Just nuke the existing pod. There is a replication controller running for both the frontend and backend:
oc get replicationcontroller
The replication controller is configured to ensure that we always have the desired number of replicas (instances) running. We can look at how many that should be:
oc describe rc ruby-hello-world-3
Note: Depending on how fast you went through previous examples, you may have only 2 replication controllers listed.
So, if we kill the pod, the RC will detect that, and fire it back up. When it
gets fired up this time, it will then have the DATABASE_SERVICE_HOST
value,
which means it will be able to connect to the DB, which means that we should no
longer see the database error!
As alice
, go ahead and find your frontend pod, and then kill it:
oc delete pod `oc get pod | grep -e "hello-world-[0-9]" | grep -v build | awk '{print $1}'`
You'll see something like:
pods/ruby-hello-world-3-wcxiw
That was the generated name of the pod when the replication controller stood it up the first time.
After a few moments, we can look at the list of pods again:
oc get pod | grep world
And we should see a different name for the pod this time:
ruby-hello-world-3-xbs3o
This shows that, underneath the covers, the RC started a new pod. Since it is a
new pod, it should have a value for the DATABASE_SERVICE_HOST
environment
variable.
As root
on the master, the following hideous command will bash-fu its way to
show you specific output from inspecting the Docker container running on the
right node:
ssh $(oc get pod -n wiring $(oc get pod -n wiring | grep -v build \
| grep world | awk {'print $1'}) -o yaml | grep host: | awk '{print $2}') \
'docker inspect $(docker ps | grep hello-world | grep run | \
awk '"'"'{print $1}'"'"')' | grep -E "DATABASE|MYSQL"
The output will look something like:
"MYSQL_USER=root",
"MYSQL_PASSWORD=redhat",
"MYSQL_DATABASE=mydb",
"DATABASE_PORT_3306_TCP_PROTO=tcp",
"DATABASE_SERVICE_HOST=172.30.145.105",
"DATABASE_PORT_3306_TCP_PORT=3306",
"DATABASE_PORT_3306_TCP_ADDR=172.30.145.105",
"DATABASE_SERVICE_PORT=3306",
"DATABASE_PORT=tcp://172.30.145.105:3306",
"DATABASE_SERVICE_PORT_MYSQL=3306",
"DATABASE_PORT_3306_TCP=tcp://172.30.145.105:3306",
Go ahead and revisit http://ruby-hello-world.wiring.cloudapps.example.com (or your appropriate FQDN) in your browser, and you should see that the application is now fully functional!