Skip to Main Content

Infrastructure Software

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

Hands-on Lab: Build and Deploy Portable Applications Using Docker

Javed A Mohammed-OracleSep 22 2015 — edited Aug 1 2016

Learn how to customize a Docker container image and use it to instantiate application instances across different Linux servers. This article describes how to create a Dockerfile, how to allocate runtime resources to containers, and how to establish a communication channel between two containers (for example, between web server and database containers).

Introduction

This hands-on lab is designed to help you get a taste for how you can use Docker to simplify application provisioning on Linux. It demonstrates how to create a Docker container on Oracle Linux, modify it, and use it to instantiate multiple application instances. It also describes how to allocate system CPU and memory resources to a Docker container, how to set up a database container, and how other containers can connect to that database container.

Getting Started

You can download a pre-built VM template for Oracle VM VirtualBox for this lab: Oracle Linux VM Images for Hands-On Lab

Once you have downloaded and imported the VM template into VirtualBox, log to the VM as holuser with the password oracle.

To use Docker, the first step is to download and install the Docker Engine RPM packages. Oracle publishes Docker Engine RPMs for Oracle Linux 6 and Oracle Linux 7 on the public yum site and on the Unbreakable Linux Network (ULN).

Up-to-date Instructions for installing the Docker Engine are available in the Oracle Linux 6 Docker User's Guide or the Oracle Linux 7 Docker User's Guide.

The initial steps are pretty simple: first enable the ol7_addons channel in /etc/yum.repos.d/public-yum-ol*.repo by using the yum-config-manager tool and then run yum install docker.

In addition, the hands-on lab image has been pre-configured with a btrfs-based filesystem for /var/lib/docker. The instructions above detail how to create and format a btrfs filesystem. The following commands assume you are logged in as the holuser user and have opened a Terminal window:

[holuser@hol10328 ~]$ sudo yum-config-manager --enable ol7_addons

[holuser@hol10328 ~]$ sudo yum install docker-engine

[holuser@hol10328 ~]$ sudo usermod -a -G docker holuser

             

You'll notice that the last command adds the holuser to the docker group. This allows the holuser to run the Docker tool and manipulate containers. In order for the group membership to take effect, please log out and then log back into the graphical user desktop.

Once Docker has been installed, we need to enable and start it using the systemd tool:

[holuser@hol10328 ~]$ sudo systemctl status docker

docker.service - Docker Application Container Engine

  Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled)

  Drop-In: /etc/systemd/system/docker.service.d

          └─docker-sysconfig.conf

  Active: inactive (dead)

    Docs: https://docs.docker.com

             

Here we can see that the Docker Engine has not been started automatically after installation. First, we need to enable the Docker Engine so that it is started automatically whenever the system boots:

[holuser@hol10328 ~]$ sudo systemctl enable docker

ln -s '/usr/lib/systemd/system/docker.service' '/etc/systemd/system/multi-user.target.wants/docker.service'

             

Next, we need to start the Docker Engine and verify that it has started correctly:

[holuser@hol10328 ~]$ sudo systemctl start docker

[holuser@hol10328 ~]$ sudo systemctl status docker

docker.service - Docker Application Container Engine

  Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled)

  Drop-In: /etc/systemd/system/docker.service.d

          └─docker-sysconfig.conf

  Active: active (running) since Sun 2015-10-04 14:15:47 PDT; 8s ago

    Docs: https://docs.docker.com

Main PID: 2427 (docker)

  CGroup: /system.slice/docker.service

          └─2427 /usr/bin/docker -d --selinux-enabled

Oct 04 14:15:22 hol10328.oracleworld.com systemd[1]: Starting Docker Application Container Engine...

...

Oct 04 14:15:47 hol10328.oracleworld.com systemd[1]: Started Docker Application Container Engine.

Hint: Some lines were ellipsized, use -l to show in full.

                

Now that the Docker Engine has started, we can check the version of both the engine and the Docker client:

[root@hol10328 ~]# docker version

Client:

Version:      1.8.2

API version:  1.20

Go version:  go1.4.2

Git commit:  390110e

Built:        Fri Sep 25 10:49:31 UTC 2015

OS/Arch:      linux/amd64

Server:

Version:      1.8.2

API version:  1.20

Go version:  go1.4.2

Git commit:  390110e

Built:        Fri Sep 25 10:49:31 UTC 2015

OS/Arch:      linux/amd64

                

We can also view information about the currently running engine, including which storage and execution drivers are active:

[root@hol10328 ~]# docker info

Containers: 0

Images: 0

Storage Driver: btrfs

Build Version: Btrfs v3.16.2

Library Version: 101

Execution Driver: native-0.2

Logging Driver: json-file

Kernel Version: 3.8.13-98.2.2.el7uek.x86_64

Operating System: Oracle Linux Server 7.1

CPUs: 1

Total Memory: 3.861 GiB

Name: hol10328.oracleworld.com

ID: D4FU:RJUB:65CH:NBLJ:UFN6:NWWY:U2CP:6PS6:4KB6:F6GX:YJSJ:6ZZL

                

The Docker Hub Registry is a public cloud store of images hosted by Docker, Inc. that can be used to build running containers. Repositories provide a mechanism for Docker image distribution and sharing. Docker, Inc. also hosts private repositories for a monthly fee. Alternatively, you can create a private Docker Registry behind your own corporate firewall, implementing protection mechanisms, such as SSL encryption and HTTP authentication, to restrict and protect access.

The following commands pull the Oracle Linux 6 and Oracle Linux 7 images from the public Docker Hub Registry, as well as the official MySQL image from Oracle, downloading them to the local machine:

[holuser@hol10328 ~]$ docker pull oraclelinux

[holuser@hol10328 ~]$ docker pull oraclelinux:6

[holuser@hol10328 ~]$ docker pull mysql/mysql-server

                

Images can include a specific tag, which indicates a particular build of that image. In the commands above, you'll notice we pulled oraclelinux first, which always points to the latest version of Oracle Linux on the Docker Hub (currently 7.1). The second command specified the specific tag "6", which indicates that we want the latest Oracle Linux 6 build. To view all the available tags, visit the image page on the Docker Hub Registry.

During the download process, you'll notice that Docker tells us when a particular filesystem layer already exists. This is because Docker creates the final filesystem for each container by layering changes. This allows Docker to optimize both downloads and cloning operations to only operate on the layers that have changes.

Next, we can view all the available images on our local machine:

[holuser@hol10328 ~]$ docker images

REPOSITORY          TAG                IMAGE ID            CREATED            VIRTUAL SIZE

mysql/mysql-server  latest              cf18a41d54bb        9 days ago          286 MB

oraclelinux          6                  5ef381c513c6        3 weeks ago        156.2 MB

oraclelinux          latest              a8fd27de55f5        3 weeks ago        189.6 MB

                

Customizing a Container for Application Provisioning

Suppose that I want to provision multiple, identical web servers across multiple Linux servers in my data center. Docker makes it easy to create a preconfigured, cookie-cutter environment in a container image. We can then use this prebuilt image and deploy it across one or many Linux hosts.

To build a customized container image, we must first build a guest container, install the web server, and configure it to deliver web server content. We can use the docker run command to run an Oracle Linux 7 base container and execute a bash shell in the guest container:

[holuser@hol10328 ~]$ docker run -t -i --name guest oraclelinux /bin/bash

                

The Docker Engine assigns an image ID to every running container instance. Because we used the arguments -i and -t, the bash shell runs interactively, and the prompt reflects the first 12 characters (f85d55a6893f) of my running container's image ID. The --name argument specifies a name for the running container instance. If you choose not to enter a name, the Docker Engine generates a random string that incorporates the name of a notable scientist, inventor, or developer, such as evil_jones; sad_ritchie; sleepy_curie and prickly_mestorf.

Open another shell and use the docker ps command to show information about the running guest container, including the shortened form of the image ID, the base image used to create this container, and the container name:

[holuser@hol10328 ~]$ docker ps

CONTAINER ID        IMAGE              COMMAND            CREATED            STATUS              PORTS              NAMES

b761e9371d83        oraclelinux        "/bin/bash"        7 seconds ago      Up 6 seconds                            guest

                

Back in the original shell and in the newly-created Docker guest, we install the httpd and perl RPM packages using yum, just as you would on any other physical or virtual server. We also use yum clean all to remove cache files that yum creates during package installation, because that will ultimately save some space in the exported container image:

[root@a1f338b303f7 /]# yum install -y httpd perl && yum clean all

ol7_UEKR3                                                                                                                                                                                  | 1.2 kB  00:00:00

ol7_latest                                                                                                                                                                                  | 1.4 kB  00:00:00

(1/5): ol7_latest/x86_64/updateinfo                                                                                                                                                        | 425 kB  00:00:00

(2/5): ol7_UEKR3/x86_64/updateinfo                                                                                                                                                          |  48 kB  00:00:00

(3/5): ol7_latest/x86_64/group                                                                                                                                                              | 652 kB  00:00:01

(4/5): ol7_UEKR3/x86_64/primary                                                                                                                                                            |  12 MB  00:00:02

(5/5): ol7_latest/x86_64/primary                                                                                                                                                            |  11 MB  00:00:02

ol7_UEKR3                                                                                                                                                                                              300/300

ol7_latest                                                                                                                                                                                        10321/10321

Resolving Dependencies

...

Installed:

  httpd.x86_64 0:2.4.6-31.0.1.el7_1.1                                                                        perl.x86_64 4:5.16.3-285.el7

...

Complete!

Cleaning repos: ol7_UEKR3 ol7_latest

Cleaning up everything

                

At this point, We need to configure some content for the web server to display. For simplicity, let's create a basic opening page in the /var/www/html directory on the guest:

[root@a1f338b303f7 /]# echo "Example Web Server Content" > /var/www/html/index.html

                

The guest container is now configured with the software environment that we want. Typing exit stops the running guest, returning to the prompt for the Linux host:

[root@b761e9371d83 /]# exit

exit

[holuser@hol10328 ~]$

                

We now need to save this modified guest as an image that can be used to create new containers. To get the ID of the modified container, we use the docker ps command with the --latest and --quiet parameters. This will output just the ID of the latest guest to be created or stopped:

[holuser@hol10328 ~]$ docker ps --latest --quiet

a1f338b303f7

                

The docker ps command lists currently running containers by default. If we run it now, there are no results (because we have no running containers at the moment):

[holuser@hol10328 ~]$ docker ps

CONTAINER ID        IMAGE              COMMAND            CREATED            STATUS              PORTS              NAMES

                

We can add the --all parameter to list both running and stopped containers:

[holuser@hol10328 ~]$ docker ps --all

CONTAINER ID        IMAGE              COMMAND            CREATED            STATUS                    PORTS              NAMES

b761e9371d83        oraclelinux        "/bin/bash"        10 minutes ago      Exited (0) 3 minutes ago                      guest

                

We can combine the output from the docker ps --latest --quiet command with the docker commit command to save the last-running guest as a new image:

[holuser@hol10328 ~]$ docker commit -m "OL7-httpd" `docker ps -l -q` hol10328/httpd:r1

910864a7dca537ca9e44a350bfd6b2cae2fa157d63ae51728d10b37c2d852fb6

                

Let's break down this command. To save an image, we use docker commit with a message (-m) parameter. We're then embedding the output of the docker ps -l -q command (using the short versions of the --latest and --quiet parameters) and finally providing a namespace, image name and tag for the image. We're saving our image into the hol10328 namespace with the image name of httpd and the tag, r1. If you want to save an image to the Docker Hub, you will need to use the namespace you created when you signed up.

If we take a look at the images now, we'll see that our image is now available:

[holuser@hol10328 ~]$ docker images

REPOSITORY          TAG                IMAGE ID            CREATED            VIRTUAL SIZE

hol10328/httpd      r1                  910864a7dca5        26 seconds ago      248.6 MB

mysql/mysql-server  latest              cf18a41d54bb        2 days ago          286 MB

oraclelinux          6                  5ef381c513c6        2 weeks ago        156.2 MB

oraclelinux          latest              a8fd27de55f5        2 weeks ago        189.6 MB

                

Deploying the Configured Docker Image

We can deploy any number of web servers now using the new Docker image as a template. The following docker run commands run the container image hol10328/httpd, creating the containers guest1, guest2, and guest3 and executing httpd in each one:

[holuser@hol10328 ~]$ docker run -d --name guest1 -p 8081:80 hol10328/httpd:r1 /usr/sbin/httpd -D FOREGROUND

f3f762543aa3a26f0cfe3aeada980fd2ebe1975e00ceedfa174821633a5891e6

[holuser@hol10328 ~]$ docker run -d --name guest2 -p 8082:80 hol10328/httpd:r1 /usr/sbin/httpd -D FOREGROUND

ca8bebb99f09b8e6c0718f06f7c34c0acfc8ee6cadc17ac16c3423c434c3ecdc

[holuser@hol10328 ~]$ docker run -d --name guest3 -p 8083:80 hol10328/httpd:r1 /usr/sbin/httpd -D FOREGROUND

4d3fe9c35884764b0fa0a0e1a791dfbfb9e1c00bd4d8963d8829dfa620c71f69

                

The -p argument maps port 80 in each guest to ports 8080, 8081, or 8082 on the host. Because we didn't use the -i or -t parameters, all three containers have started in the background. We can use the docker ps command to show the running guests:

[holuser@hol10328 ~]$ docker ps

CONTAINER ID        IMAGE              COMMAND                  CREATED            STATUS              PORTS                  NAMES

87adc4cf1510        hol10328/httpd:r1  "/usr/sbin/httpd -D F"  2 seconds ago      Up 1 seconds        0.0.0.0:8083->80/tcp  guest3

61fe9a593431        hol10328/httpd:r1  "/usr/sbin/httpd -D F"  6 seconds ago      Up 6 seconds        0.0.0.0:8082->80/tcp  guest2

8a8bdc289370        hol10328/httpd:r1  "/usr/sbin/httpd -D F"  11 seconds ago      Up 11 seconds      0.0.0.0:8081->80/tcp  guest1

                

The default IP address value of 0.0.0.0 means that the port mapping applies to all network interfaces on the host. Using a web browser or curl, we can test the web server running in each guest:

[holuser@hol10328 ~]$ curl http://hol10328:8081

Example Web Server Content

[holuser@hol10328 ~]$ curl http://hol10328:8082

Example Web Server Content

[holuser@hol10328 ~]$ curl http://hol10328:8083

Example Web Server Content

                

Using a Dockerfile

Now that you've seen how to create and manipulate Docker containers using the command line, the preferred way to build and customize containers is actually using Dockerfiles. A Dockerfile is a small text file that contains the instructions required to construct a container. When a Dockerflle is built, each instruction adds a layer to the container in a step-by-step process. The build creates a container, runs the next instruction in that container, and then commits the container. Docker then runs the committed image as the basis for adding the next layer. The benefit of this layered approach is that Dockerfiles with the same initial instructions reuse layers.

Dockerfiles also create an easily readable and modifiable record of the steps used to create a Docker image. Publishing a Dockerfile to the public Docker Hub or to an internal repository is generally the preferred method of creating and sharing Docker images.

To create a Dockerfile, first create a directory for it:

[holuser@hol10328 ~]$ mkdir ~/dockerfile-httpd

[holuser@hol10328 ~]$ cd ~/dockerfile-httpd/

                

In that directory, use a text editor to create a file called Dockerfile that contains the following contents:

# Dockerfile for creating a Docker image for OL 7 and httpd and perl

FROM oraclelinux

MAINTAINER E. Jones <ejones@email-address.com>

RUN yum install -y httpd perl && yum clean all

RUN echo "Example Web Server Content" > /var/www/html/index.html

EXPOSE 80

CMD /usr/sbin/httpd -D FOREGROUND

                

This Dockerfile reflects the same steps as the previous exercise in which we manually built the Docker image for my web server: it configures a new container from a base Oracle Linux 7 image, installs the httpd and perl RPMs, and adds placeholder content for the opening web page.

The docker build command constructs a new Docker image from this Dockerfile, creating and removing temporary containers as needed during its step-by-step build process:

[holuser@hol10328 ~]$ docker build -t hol10328/httpd:r2 ~/dockerfile-httpd/.

Sending build context to Docker daemon 2.048 kB

Step 0 : FROM oraclelinux

---> a8fd27de55f5

Step 1 : MAINTAINER E. Jones <ejones@email-address.com>

---> Running in 5e47026bd9ac

---> 6c954581d8d7

Removing intermediate container 5e47026bd9ac

Step 2 : RUN yum install -y httpd perl && yum clean all

---> Running in 9e7de7675e9f

Resolving Dependencies

--> Running transaction check

---> Package httpd.x86_64 0:2.4.6-31.0.1.el7_1.1 will be installed

...

---> Package perl.x86_64 4:5.16.3-285.el7 will be installed

...

--> Running transaction check

...

Installed:

  httpd.x86_64 0:2.4.6-31.0.1.el7_1.1        perl.x86_64 4:5.16.3-285.el7

...

Complete!

Cleaning repos: ol7_UEKR3 ol7_latest

Cleaning up everything

---> 216c72f21d9b

Removing intermediate container 9e7de7675e9f

Step 3 : RUN echo "Example Web Server Content" > /var/www/html/index.html

---> Running in 099d2d0420c9

---> a4b3da2df721

Removing intermediate container 099d2d0420c9

Step 4 : EXPOSE 80

---> Running in 4381004b4686

---> c81647c23fb5

Removing intermediate container 4381004b4686

Step 5 : CMD /usr/sbin/httpd -D FOREGROUND

---> Running in bd6df764edef

---> 2e6f94af4d8f

Removing intermediate container bd6df764edef

Successfully built 2e6f94af4d8f

                

The docker images command lists the new hol10328/httpd:r2 image created from the Dockerfile:

[holuser@hol10328 ~]$ docker images

REPOSITORY          TAG                IMAGE ID            CREATED            VIRTUAL SIZE

hol10328/httpd      r2                  2e6f94af4d8f        52 seconds ago      248.6 MB

hol10328/httpd      r1                  910864a7dca5        12 minutes ago      248.6 MB

mysql/mysql-server  latest              cf18a41d54bb        2 days ago          286 MB

oraclelinux          6                  5ef381c513c6        2 weeks ago        156.2 MB

oraclelinux          latest              a8fd27de55f5        2 weeks ago        189.6 MB

                

Limiting Runtime Resources

A Docker container uses underlying control group (cgroup) technologies, creating a cgroup for each Docker container. Cgroups provide useful capabilities, such as collecting metrics for CPU, memory, and block I/O usage and providing resource management capabilities. For each Docker container, you can find metrics in the host's corresponding cgroup hierarchy; for example, on an Oracle Linux 7 host running the Unbreakable Enterprise Kernel Release 3 (UEKR3), a memory.stat file in the directory /sys/fs/cgroup/memory/system.slice/docker-<container ID> lists memory-related metrics for that container. (See the Docker blog article "Gathering LXC and Docker containers metrics.")

The docker run command provides options that enable runtime limits for memory and relative CPU allocations. These options provide a degree of resource control when executing container images. The -m or --memory option limits the amount of physical and swap memory available to processes within a container. For example, the following command places a limit of 256 MB for physical memory (and up to 512 MB for memory plus swap):

[holuser@hol10328 ~]$ docker run -d --memory=256m --name guest10 -p 8090:80 hol10328/httpd:r2

bcbd59911607b8f22e5731b5a174b24513415a9b9e47a2429343524003cb9762

                

The -c or --cpushares option provides a method of assigning a relative number of CPU shares:

[holuser@hol10328 ~]$ docker run -d --cpu-shares=512 --name guest11 -p 8091:80 hol10328/httpd:r2

b5eaa43c5e8fdf3caafe69b63cdbeaab94cd90ea5c153ec2b794b4484ff8b051

                

By default, a container gets 1024 CPU shares, so in this example, the guest2 container gets a relative 50 percent share of the available computing resources. Note that the host kernel applies limits only when there is resource contention. For example, if guest2 is assigned 512 shares (50 percent, as shown above) and guest1 is assigned 1024 shares (100 percent), processes in guest2 will still get 100 percent of the available CPU resources if all guest1 processes are idle.

For more information about options to the docker run command, enter docker run --help or see the Docker run reference guide.

Connecting a Web Server Container to a MySQL Container

Suppose we want to connect my web server container to a container running an instance of MySQL. Docker makes it possible to link containers together, creating a secure channel for one container to access certain information from another.

Previously we pulled the Oracle MySQL image from the Docker Hub using the command docker pull mysql/mysql-server. To run the MySQL image as a container named db, we need to create a location to store the MySQL data and start a new container:

[holuser@hol10328 ~]$ cd ~

[holuser@hol10328 ~]$ mkdir mysql-datadir

[holuser@hol10328 ~]$ docker run --name db -d -e MYSQL_ROOT_PASSWORD=Oracle123 -e MYSQL_DATABASE=webdb -e MYSQL_USER=webuser -e MYSQL_PASSWORD=secret -v /home/holuser/mysql-datadir/:/var/lib/mysql mysql/mysql-server

       

Let's break down the run command: we start a container named db in the background using the -d (detached) parameter. We then set a series of environment variables using multiple -e parameters. The MySQL image allows you to customize the database that is created on startup by using environment variables to configure the container. In this example, we are setting the MySQL root password to Oracle123 and creating a new database called webdb. We then create a new MySQL user called webuser with the password of secret. The container automatically assigns the correct permission to the user for the database it creates.

Using the -v or --volume flag is how you can associate database storage (or, in general, any files or folders) that a Docker container needs to change while it's running. Remember that Docker containers are "ephemeral"; that is, they are transient in nature and data does not persist beyond the lifespan of a container's execution. Associating a data volume with a container using the -v flag allows the container to access, modify, and persist data on the host.

Reminiscent of an NFS mount, the -v flag causes the directory /home/holuser/mysql-datadir on the host to be mounted as /var/lib/mysql (the default database location for MySQL) on the container. From an operational standpoint, the ability to mount a database directory as a container volume in this way also provides an easy way to enable database backups.

The Docker Hub mysql/mysql-server image includes an entrypoint script (entrypoint.sh) that sets up the database server automatically, initializing mysqld. We can view log messages generated from a container using the docker logs command:

[holuser@hol10328 ~]$ docker logs db

Running mysql_install_db

2015-10-11 22:21:42 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).

2015-10-11 22:21:42 0 [Note] /usr/sbin/mysqld (mysqld 5.6.27) starting as process 12 ...

...

Finished mysql_install_db

MySQL init process in progress...

...

2015-10-11 22:21:50 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).

2015-10-11 22:21:50 0 [Note] mysqld (mysqld 5.6.27) starting as process 1 ...

                

We now have a MySQL container running. Next, we need to create a web server container than contains code to connect to the database and retrieve information.

Let's create a new Dockerfile that configures a web server that includes some Perl scripts:

[holuser@hol10328 ~]$ cd ~

[holuser@hol10328 ~]$ mkdir dockerfile-linked-httpd && cd dockerfile-linked-httpd

     

Use your favourite text editor to create a Dockerfile with the following content:

FROM oraclelinux:7

RUN yum install -y httpd perl perl-DBI.x86_64 libdbi-dbd-mysql.x86_64 perl-DBD-MySQL.x86_64 && yum clean all

ADD version.pl /var/www/cgi-bin/version.pl

RUN chmod 755 /var/www/cgi-bin/version.pl

ADD initdb.pl /var/www/cgi-bin/initdb.pl

RUN chmod 755 /var/www/cgi-bin/initdb.pl

ADD doquery.pl /var/www/cgi-bin/doquery.pl

RUN chmod 755 /var/www/cgi-bin/doquery.pl

EXPOSE 80

ENTRYPOINT /usr/sbin/httpd -D FOREGROUND

                

This Dockerfile introduces the new command ADD which allows us to add a file from the host into the container during build. In order to successfully build this container, we need to create the three Perl scripts on the host, in the same directory as the Dockerfile itself.

version.pl:

#!/usr/bin/perl

use DBI;

print "Content-type: text/html\n\n";

my $dbh = DBI->connect(

    "dbi:mysql:dbname=webdb:host=db",

        "webuser",

        "secret",

        { RaiseError => 1 },

) or die $DBI::errstr;

my $sth = $dbh->prepare("SELECT VERSION()");

$sth->execute();

my $ver = $sth->fetch();

print "Version = ", @$ver, "\n";

$sth->finish();

$dbh->disconnect()

                

initdb.pl

#!/usr/bin/perl

use strict;

use DBI;

print "Content-type: text/html\n\n";

my $dbh = DBI->connect(

    "dbi:mysql:dbname=webdb:host=db",

    "webuser",

    "secret",

    { RaiseError => 1}

) or die $DBI::errstr;

$dbh->do("DROP TABLE IF EXISTS People");

$dbh->do("CREATE TABLE People(Id INT PRIMARY KEY, Name TEXT, Age INT) ENGINE=InnoDB");

$dbh->do("INSERT INTO People VALUES(1,'Alice',42)");

$dbh->do("INSERT INTO People VALUES(2,'Bobby',27)");

$dbh->do("INSERT INTO People VALUES(3,'Carol',29)");

$dbh->do("INSERT INTO People VALUES(4,'Daisy',20)");

$dbh->do("INSERT INTO People VALUES(5,'Eddie',35)");

$dbh->do("INSERT INTO People VALUES(6,'Frank',21)");

my @noerr = ('Rows inserted in People table');

print @noerr;

print "\n";

my $sth = $dbh->prepare( "SELECT * FROM People" );

$sth->execute();

for ( 1 .. $sth->rows() ) {

    my ($id, $name, $age) = $sth->fetchrow();

    print "$id $name $age\n";

}

$sth->finish();

$dbh->disconnect();

                

doquery.pl

#!/usr/bin/perl

use strict;

use DBI;

print "Content-type: text/html\n\n";

my $dbh = DBI->connect(

    "dbi:mysql:dbname=webdb;host=db",

        "webuser",

        "secret",

        { RaiseError => 1 },

) or die $DBI::errstr;

my $sth = $dbh->prepare( "SELECT * FROM People WHERE Age > $ARGV[0]" );

$sth->execute();

my $fields = $sth->{NUM_OF_FIELDS};

my $rows = $sth->rows();

print "Selected $rows row(s) with $fields field(s)\n";

for ( 1 .. $rows ) {

    my ($id, $name, $age) = $sth->fetchrow();

    print "$id $name $age\n";

}

$sth->finish();

$dbh->disconnect();

                

These three scripts will allow us to create a basic MySQL database using initdb.pl, then query the MySQL server using version.pl and finally query the MySQL database we created using doquery.pl.

Before we can run the web server, we need to build a new image using the docker build command. Using what you learned in the previous exercise, build a new Docker image for hol10328/httpd with the tag R3.

Once your new Docker image is created, you can run it:

[holuser@hol10328 dockerfile-linked-httpd]$ docker run -d --name webdb -p 8080:80 --link db:db hol10328/httpd:r3

                

By linking containers using the --link flag, other application containers can access the MySQL database running in the db container. This simplifies the separation of database, application, and web services, making it easier to isolate services in different containers. Docker automatically configures networking and the /etc/hosts file in each linked container.

Finally, we can run the Perl scripts in the web server container to create and query the database running in the database container

[holuser@hol10328 dockerfile-linked-httpd]$ curl http://hol10328:8080/cgi-bin/version.pl

Version = 5.6.27

[holuser@hol10328 dockerfile-linked-httpd]$ curl http://hol10328:8080/cgi-bin/initdb.pl

Rows inserted in People table

1 Alice 42

2 Bobby 27

3 Carol 29

4 Daisy 20

5 Eddie 35

6 Frank 21

[holuser@hol10328 dockerfile-linked-httpd]$ curl http://hol10328:8080/cgi-bin/doquery.pl?30

Selected 2 row(s) with 3 field(s)

1 Alice 42

5 Eddie 35

[holuser@hol10328 dockerfile-linked-httpd]$ curl http://hol10328:8080/cgi-bin/doquery.pl?21

Selected 4 row(s) with 3 field(s)

1 Alice 42

2 Bobby 27

3 Carol 29

5 Eddie 35

                

The Oracle Linux documentation includes a detailed example of how to link a web container with a MySQL database, and it provides sample scripts that configure httpd.conf, create a database, and perform queries. Additional background on linking containers and using data volumes is available there and also in the Docker user guide.

Comments

Hoek

Just use the search box on the upper left on this page: Oracle Database Online Documentation 11g Release 2 (11.2)

Frank Kulash

Hi,

Post your answers, and specific questions about them.  (For example, if you're not sure what the question means, or how to find the answer, or if your answer really applies to all situations).

Let's take the last question you posted, for example:
"39. how many hints are there provided by oracle?"

You might wonder if they really expect an exact number, or if an approximation is good enough.  You might not know which manual contains the answer, or what keyword(s) to look up in the index to find the answer.

SomeoneElse

> please give me the answers for all.

You're kidding, right?


Chris Hunt
Please give me the answers for all.

Sure. Please give me all the money you get from the job, since it's me that'll be answering all the interview questions.

SomeoneElse

Actually, if I were to present these questions to a potential candidate the answer I'd want to hear is "wow, what a bunch of shitty questions".


Frank Kulash

Hi,

SomeoneElse wrote:

Actually, if I were to present these questions to a potential candidate the answer I'd want to hear is "wow, what a bunch of shitty questions".

Not entirely.

Some certainly are poor questions. Some require clarification; they might have meant something reasonable.

Some aren't bad interview questions.  For example:

"6. what is mutating table error? how can you solve that problem?"

I think this question is okay.  It is a common enough problem; and there are different ways (some good, some terrible) to deal with the problem.  How the candidate answers this question can tell you a lot about the candidate's experience and intelligence.

Hoek

Yup, most of those questions are outdated, from the previous century, or badly phrased....now "shall we create a table in the procedure"?

Mike Kutz

SomeoneElse

I partly agree with you, but I'd be more interested in hearing the person's reason on why they are bad questions.

On the other hand, if a person with zero(0) knowledge asks the questions, the local guru can then judge the candidate's capability of communicating Oracle concepts (to others) based on how much the interviewee has learned.

In that sense, the questions are perfect.

(except some of the syntax related ones)

MK

bandarupalli

yes these bunch of shitty questions are been asked by the interviewers....

because people like me are kids and people like you are dinosaurs in sql,pl/sql i thought...

but this is the platform which is connecting masters like you and learners like me so i'm requesting you to get answered ....

please help us .. if you can...

thanks in advance

SomeoneElse

>  learners like me so i'm requesting you to get answered ....

OK, but are you really interested in learning or just memorizing some answers to get through the next interview?

EdStevens

Where did you get this list?

A good interviewer doesn't necessarily ask questions as if it is a multiple choice or true/false test, but rather to see how the interviewee handles the question ... they aren't looking to see if you have a memorized answer but rather to evaluate how you go about solving a problem or if you are at least familiar with the resources available to help solve a problem.  I've even been known to pose a question that implies/assumes a falsehood, specifically to see if the candidate could catch it or if they would try to blow smoke.

It should be perfectly acceptable to respond with "that is a detail I can look up in <name the manual> when needed."

=================================================

Learning how to look things up in the documentation is time well spent investing in your career.  To that end, you should drop everything else you are doing and do the following:

Go to  docs.oracle.com.

Locate the link for your Oracle product and version, and click on it.

You are now at the entire documentation set for your selected Oracle product and version.

BOOKMARK THAT LOCATION

Spend a few minutes just getting familiar with what is available here. Take special note of the "books" and "search" tabs. Under the "books" tab (for 10.x) or the "Master Book List" link (for 11.x) you will find the complete documentation library.

Spend a few minutes just getting familiar with what kind of documentation is available there by simply browsing the titles under the "Books" tab.

Open the Reference Manual and spend a few minutes looking through the table of contents to get familiar with what kind of information is available there.

Do the same with the SQL Reference Manual.

Do the same with the Utilities manual.

You don't have to read the above in depth.  They are reference manuals.  Just get familiar with what is there to be referenced. Ninety percent of the questions asked on this forum can be answered in less than 5 minutes by simply searching one of the above manuals.

Then set yourself a plan to dig deeper.

- *Read a chapter a day from the Concepts Manual*.

- Take a look in your alert log.  One of the first things listed at startup is the initialization parms with non-default values. Read up on each one of them (listed in your alert log) in the Reference Manual.

- Take a look at your listener.ora, tnsnames.ora, and sqlnet.ora files. Go to the Network Administrators manual and read up on everything you see in those files.

- *When you have finished reading the Concepts Manual, do it again*.

Give a man a fish and he eats for a day. Teach a man to fish and he eats for a lifetime.

=================================

bandarupalli

i wanna know them not answers but the concepts ....

reading some hundreds of pages is different to get explained..

i thought it was the right platform to learn, it is not big deal of interview but they are not getting satisfied with my answers because i have to learn something else not from books...

thats why i put almost all questions( even silly ones)

Thankyou

Frank Kulash

Hi,

This forum is a great place for people to ask questions and get them answered.  That doesn't mean it's the best place to get all questions answered.  Forums like this work best for specific, focused questions.  I gave some examples earlier of some specific, focused things you might ask about those interview questions.  "Answer these 39 questions." isn't a specific, focused question.   For one thing, it invites answers that cover things you already know, and don't help with what you need to learn.  Some examples of specific focused questions that can help you learn are:

  • "When they ask ... do they mean ... or do they mean  ...?"
  • "For this interview question ...is this a good answer: ...?  I'm not confident about ..."
  • "How would I find the answer to ...?  What buzzwords whould I look for?"
  • "For this interview question ... I looked up ... where it says...  Is that right?  It seems wrong to me because ..."
  • "Why would they ask something like ... on an interview?  Are they looking for an aswere such as ...?"
  • "Where can I learn more about ...?  I tried ... but ..."

Most people who answer questions on this forum are interested in helping you learn.  "If you give a man he fish, he will eat for a single day.  If you show him how to fish, he may eat for a lifetime."  Many people whould add "If you beat him over the head with a fish, he'll quit asking you for handouts."

Billy Verreynne

bandarupalli wrote:

yes these bunch of shitty questions are been asked by the interviewers....

because people like me are kids and people like you are dinosaurs in sql,pl/sql i thought...

but this is the platform which is connecting masters like you and learners like me so i'm requesting you to get answered ....

please help us .. if you can...

thanks in advance

The questions are shitty because.. well they are. They do not measure PL/SQL or Oracle expertise in any way. Here's my answers to a few of these interview questions.

5. what is the third parameter of the raise_application_error()?

Look it up in the fricken manual idiot. Besides. not wrapping a system call like that in an application wrapper is the problem.

6. what is mutating table error? how can you solve that problem?

The problem is solved by putting brain in gear before doing a physical database design of the logical data model, instead of using triggers as sticky tape to glue cr@p together.

27. shall we create a table in the package?

Yes we can - as all packages are not application interfaces and an API can be a system level API and deal with data management. There are no such rule of "Thou shalt not use DDL in PL/SQL", except for in the mind of the ignorant.

And this is why the questions are shitty. It pretend to measure expertise, but are horribly flawed as these questions are based on assumptions and exceptions, and presuppositions, with a poor understanding of what technical expertise is, and a very limited understanding of actual Oracle technologies.

In other words, these are random interview questions pulled from blogs about Oracle and Oracle related problems - and not even good blogs... (never mind using the fricken Concepts Guide to probe the understanding of the person being interviewed of Oracle fundamentals).

I would not take kindly to being asked such questions in an interview.

BluShadow

Billy, you're hired!

Billy Verreynne

The single most critical question - what is the availability of filter coffee at workplace like? And if not 99.9999% during the hours of 6AM to 4PM, then no thanks.

BluShadow

Each department has it's own kitchen so you can make whatever drinks you like for yourself.

Plus the canteen has a Costa (lotta) Coffee facility. 

Me personally, I'm not a coffee drinker. 

1 - 17

Post Details

Added on Sep 22 2015
6 comments
15,254 views