Monday, 11 February 2019

Bash - Conditions and loops

Again, an aide memoire

A Bash script that tests for a single input, and moans if none are found: -

cat plob.sh 

#!/bin/bash

if [ -z "$1" ]
  then
    echo "For what product are you creating this ?"
    exit 1
  else
    echo $1

fi

With no argument ....

./plob.sh 

For what product are you creating this ?

With one argument ...

./plob.sh BPM

BPM

With multiple arguments ....

./plob.sh BPM ODM

BPM

In other words, only the first argument is used ...

A Bash script that tests for TWO arguments: -

cat plab.sh 

#!/bin/bash
if [ $# = 2 ]
then
echo "Nice arguments"
else
echo "More arguments, please"
exit 1
fi

With no argument ...

./plab.sh 

More arguments, please

With one argument ...

./plab.sh BPM

More arguments, please

With two arguments ...

./plab.sh BPM ODM

Nice arguments

A Bash script that tests for TWO arguments: -

cat plib.sh 

#!/bin/bash
echo $#
if [ -z "$1"  ] & [ -z "$2" ]
then
        echo "Usage: Two arguments please"
        exit 1
else
echo $1 $2
fi

With no argument ...

./plib.sh 

0
Usage: Two arguments please

./plib.sh BPM

1
Usage: Two arguments please

./plib.sh BPM ODM

2
BPM ODM

So, for reference, we're using the following: -

$# - Counts the arguments
#1 - Argument 1
#2 - Argument 2
-z - Checks whether the arguments are empty 

From a looping perspective, I've used this one many times before ....

A Bash script that unpacks some TAR files: -

for i in /tmp/*.tar.gz; do tar xvzf $i -C /tmp/snafu; done

This is with what we started: -

ls -al *.tar.gz

-rw-r--r--  1 hayd  wheel  135 11 Feb 16:22 billing.tar.gz
-rw-r--r--  1 hayd  wheel  154 11 Feb 16:22 docs.tar.gz
-rw-r--r--  1 hayd  wheel  138 11 Feb 16:22 preso.tar.gz

and this is what we ended: -

ls -al /tmp/snafu/

total 0
drwxr-xr-x   6 hayd  wheel  192 11 Feb 16:23 .
drwxrwxrwt  21 root  wheel  672 11 Feb 16:22 ..
-rw-r--r--   1 hayd  wheel    0 11 Feb 16:22 Expenses.xls
-rw-r--r--   1 hayd  wheel    0 11 Feb 16:21 Journal.doc
-rw-r--r--   1 hayd  wheel    0 11 Feb 16:22 Presentation.ppt
-rw-r--r--   1 hayd  wheel    0 11 Feb 16:21 Readme.doc

Final thing, with tar, we use -C to specify the target directory and for unzip, we use -d to specify the target directory.

Aide Memoire - Docker Tinkerings

Writing it down here so that I don't forget .....

A quick run-down of some of my most useful Docker commands: -

See what's running

docker ps -a

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

See what images I have

docker images

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

Run, and pull - if needed, a Docker container

docker run hello-world

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
1b930d010525: Pull complete 
Digest: sha256:2557e3c07ed1e38f26e389462d03ed943586f744621577a99efb77324b0fe535
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

See what images I have

docker images

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

hello-world         latest              fce289e99eb9        5 weeks ago         1.84kB

See what images I have - without truncation

docker images --no-trunc

REPOSITORY          TAG                 IMAGE ID                                                                  CREATED             SIZE

hello-world         latest              sha256:fce289e99eb9bca977dae136fbe2a82b6b7d4c372474c9235adc1741675f587e   5 weeks ago         1.84kB

See what's running

docker ps -a

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES

3d0a99dfd9a4        hello-world         "/hello"            16 seconds ago      Exited (0) 15 seconds ago                       frosty_hypatia

See what's running - without truncation

docker ps -a --no-trunc

CONTAINER ID                                                       IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES
3d0a99dfd9a47cd9e336d56ab2fc83bd78ca80978d971dc276946041fdb40995   hello-world         "/hello"            21 seconds ago      Exited (0) 19 seconds ago                       frosty_hypatia

See what's under the hood - in terms of layers

docker history fce289e99eb9

IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
fce289e99eb9        5 weeks ago         /bin/sh -c #(nop)  CMD ["/hello"]               0B                  
          5 weeks ago         /bin/sh -c #(nop) COPY file:f77490f70ce51da2…   1.84kB              

And with a slightly (!) more advanced Docker image: -

docker run docker/whalesay cowsay boo

Unable to find image 'docker/whalesay:latest' locally
latest: Pulling from docker/whalesay
e190868d63f8: Pull complete 
909cd34c6fd7: Pull complete 
0b9bfabab7c1: Pull complete 
a3ed95caeb02: Pull complete 
00bf65475aba: Pull complete 
c57b6bcc83e3: Pull complete 
8978f6879e2f: Pull complete 
8eed3712d2cf: Pull complete 
Digest: sha256:178598e51a26abbc958b8a2e48825c90bc22e641de3d31e18aaf55f3258ba93b
Status: Downloaded newer image for docker/whalesay:latest

 _____ 
< boo >
 ----- 
    \
     \
      \     
                    ##        .            
              ## ## ##       ==            
           ## ## ## ##      ===            
       /""""""""""""""""___/ ===        
  ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ /  ===- ~~~   
       \______ o          __/            
        \    \        __/             
          \____\______/   


docker images

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello-world         latest              fce289e99eb9        5 weeks ago         1.84kB
docker/whalesay     latest              6b362a9f73eb        3 years ago         247MB

docker history 6b362a9f73eb

IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
6b362a9f73eb        3 years ago         /bin/sh -c #(nop) ENV PATH=/usr/local/bin:/u…   0B                  
          3 years ago         /bin/sh -c sh install.sh                        30.4kB              
          3 years ago         /bin/sh -c git reset --hard origin/master       43.3kB              
          3 years ago         /bin/sh -c #(nop) WORKDIR /cowsay               0B                  
          3 years ago         /bin/sh -c git clone https://github.com/moxi…   89.9kB              
          3 years ago         /bin/sh -c apt-get -y update && apt-get inst…   58.6MB              
          3 years ago         /bin/sh -c #(nop) CMD ["/bin/bash"]             0B                  
          3 years ago         /bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$…   1.9kB               
          3 years ago         /bin/sh -c echo '#!/bin/sh' > /usr/sbin/poli…   195kB               
          3 years ago         /bin/sh -c #(nop) ADD file:f4d7b4b3402b5c53f…   188MB         

docker inspect 6b362a9f73eb

[
    {
        "Id": "sha256:6b362a9f73eb8c33b48c95f4fcce1b6637fc25646728cf7fb0679b2da273c3f4",
        "RepoTags": [
            "docker/whalesay:latest"
        ],
        "RepoDigests": [
            "docker/whalesay@sha256:178598e51a26abbc958b8a2e48825c90bc22e641de3d31e18aaf55f3258ba93b"
        ],
        "Parent": "",
        "Comment": "",
        "Created": "2015-05-25T22:04:23.303454458Z",
        "Container": "5460b2353ce4e2b3e3e81b4a523a61c5adc238ae21d3ec3a5774674652e6317f",
        "ContainerConfig": {
            "Hostname": "9ec8c01a6a48",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/bin/sh",
                "-c",
                "#(nop) ENV PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Image": "5d5bd9951e26ca0301423625b19764bda914ae39c3f2bfd6f1824bf5354d10ee",
            "Volumes": null,
            "WorkingDir": "/cowsay",
            "Entrypoint": null,
            "OnBuild": [],
            "Labels": {}
        },
        "DockerVersion": "1.6.0",
        "Author": "",
        "Config": {
            "Hostname": "9ec8c01a6a48",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/bin/bash"
            ],
            "Image": "5d5bd9951e26ca0301423625b19764bda914ae39c3f2bfd6f1824bf5354d10ee",
            "Volumes": null,
            "WorkingDir": "/cowsay",
            "Entrypoint": null,
            "OnBuild": [],
            "Labels": {}
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 247049019,
        "VirtualSize": 247049019,
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/793768003cdb0f4c4b76627e2fdaef447af26a570f293c9cd0efd4e93c980cea/diff:/var/lib/docker/overlay2/2b675a0417a328024a4d12480cbc8d59655c3fba039c870057cd37537e5bd05b/diff:/var/lib/docker/overlay2/2e2deecb066dd3582e77ffe750975cde90e45c77cce842be439e0ca5c4f0d0f6/diff:/var/lib/docker/overlay2/6f5991826733cb88f5e356deb6807ffb58160072cef0db687a5d9820bc7e3ba0/diff:/var/lib/docker/overlay2/84adea855c8ed41a82c005e381d5a3d31f9b5a84579fb0bc644d707c90f54dd3/diff:/var/lib/docker/overlay2/95b856d151d6253bc8311c4ab6908893274e7162517ac265e739a544da9f9190/diff:/var/lib/docker/overlay2/d3bfc7095c61ef75f4943fe3f9926c275b30a434e5af0dd276b2b635834b4467/diff:/var/lib/docker/overlay2/d0aa0bcc22e6a4bd5511d9e7933869cbcc4794087fa1520f77199597328a4f5c/diff:/var/lib/docker/overlay2/2ba2e03e60d5e8e0c84fcb59941417607ee78265f2545fe2cb4a489dd1dbd186/diff",
                "MergedDir": "/var/lib/docker/overlay2/db32366024b39eb798f94baa6a84ca982ecbf7c575bed43aecc32ec137ebb180/merged",
                "UpperDir": "/var/lib/docker/overlay2/db32366024b39eb798f94baa6a84ca982ecbf7c575bed43aecc32ec137ebb180/diff",
                "WorkDir": "/var/lib/docker/overlay2/db32366024b39eb798f94baa6a84ca982ecbf7c575bed43aecc32ec137ebb180/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:1154ba695078d29ea6c4e1adb55c463959cd77509adf09710e2315827d66271a",
                "sha256:528c8710fd95f61d40b8bb8a549fa8dfa737d9b9c7c7b2ae55f745c972dddacd",
                "sha256:37ee47034d9b78f10f0c5ce3a25e6b6e58997fcadaf5f896c603a10c5f35fb31",
                "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef",
                "sha256:b26122d57afa5c4a2dc8db3f986410805bc8792af3a4fa73cfde5eed0a8e5b6d",
                "sha256:091abc5148e4d32cecb5522067509d7ffc1e8ac272ff75d2775138639a6c50ca",
                "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef",
                "sha256:d511ed9e12e17ab4bfc3e80ed7ce86d4aac82769b42f42b753a338ed9b8a566d",
                "sha256:d061ee1340ecc8d03ca25e6ca7f7502275f558764c1ab46bd1f37854c74c5b3f",
                "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef"
            ]
        },
        "Metadata": {
            "LastTagTime": "0001-01-01T00:00:00Z"
        }
    }
]

Bash - permissions say "Yes" but script no go

I saw this on Friday - bit of a learning curve for someone who thought he knew Unix :-)

I'd created a script: -

vi /tmp/sayHello.sh

#!/bin/bash
echo "Hello World!"

and made it executable: -

chmod +x /tmp/sayHello.sh

and validated it: -

 ls -al /tmp/sayHello.sh 

-rwxrwxr-x 1 daveh daveh 32 Feb 11 14:53 /tmp/sayHello.sh

but, when I tried to execute it: -

/tmp/sayHello.sh

-bash: /tmp/sayHello.sh: Permission denied

I even tried as root: -

su -

whoami

root

ls -al /tmp/sayHello.sh 

-rwxrwxr-x 1 daveh daveh 32 Feb 11 14:53 /tmp/sayHello.sh

/tmp/sayHello.sh

-bash: /tmp/sayHello.sh: Permission denied

It took me a while .... with the kind support of a colleague ... to realise where I was going wrong.

I had ASSUMED that there'd be no issue running a script from /tmp ......

You know what they say about assumptions, right ?

It transpired that, for this particular Ubuntu box, the /tmp file-system was mounted with the noexec bit set.

This was evidenced via the mount command, which returned: -

...
tmpfs on /tmp type tmpfs (rw,nosuid,nodev,noexec,relatime,mode=777)
...

I simulated the same situation with a RHEL box: -

mkdir /foobar

vi /foobar/sayHello.sh

#!/bin/bash
echo "Hello World!"

chmod +x /foobar/sayHello.sh

mkdir /snafu

mount -o bind /foobar /snafu

/snafu/sayHello.sh 

Hello World!

mount -o remount,noexec,nosuid,nodev,bind /foobar/ /snafu

/snafu/sayHello.sh 

-bash: /snafu/sayHello.sh: Permission denied

In this example, I'm using mount -o bind and mount -o remount to simulate the /tmp file-system on the Ubuntu boxen, rather than creating a new file-system.

However, the point remains the same - I did not know about the noexec ( and corresponding nosuid and nodev mount options - as evidenced here: -

/dev/mapper/rhel-root on /snafu type xfs (rw,nosuid,nodev,noexec,relatime,seclabel,attr2,inode64,noquota)


AWK - It's my "new" best friend forever ....

Nobody can accuse me of being late to the party ....

Well, OK, some *nix l33t can accuse me of being late to the party ....

So, whilst I've been tinkering with sed ( Stream Editor ) for years, albeit in a very very very minimal way, as per this example: -

sed -i'' "s/PidFile\ logs/PidFile\ ${Product}\/logs/g" /opt/ibm/HTTPServer/${Product}/conf/httpd.conf

I have mainly managed to avoid using AWK for no particular reason other than lack of need.

However, recently, I've wanted to grab specific columns from output such as: -

docker ps -a

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                  PORTS               NAMES
51e1af565b7e        ibmcom/ace:latest   "runaceserver"      5 days ago          Exited (0) 4 days ago                       ace
3d8899de8f32        hello-world         "/hello"            5 days ago          Exited (0) 5 days ago                       happy_colden

where I just want the CONTAINER ID column: -

docker ps -a | awk '{print $1}'

which gives me this: -

CONTAINER
51e1af565b7e
3d8899de8f32

where awk is only printing the first column using print $1.

Better still: -

docker ps -a | sed 1d | awk '{print $1}'

51e1af565b7e
3d8899de8f32

which uses sed 1d to delete the first row of the output from docker ps -a and then let awk do its thing.

Similarly, I wanted to grab a specific attribute ( cgroup ) from the output of the ps -elf process listing.

Ordinarily, this command would return a whole slew of columns: -

F S UID        PID  PPID  C PRI  NI ADDR SZ WCHAN  STIME TTY          TIME CMD
4 S root         1     0  0  80   0 -  3158 ep_pol 10:44 ?        00:00:00 systemd --no-pager
...

So I want to lose the first row and only print column 4 ( PID ) to get a list of process IDs, and then run ps -o cgroup against the resulting list.

This is how I did it: -

ps -o cgroup `ps -elf | sed 1d | awk '{print $4}'`

which did the job: -

CGROUP
14:name=systemd:/init.scope,0::/init.scope
14:name=systemd:/system.slice/systemd-journald.service,12:pids:/system.slice/systemd-journald.service,6:devices:/system.slice/systemd-journald.service,5:memory:/system.slice/systemd-journald.service,4:blkio:/syst
...

I could've then put the resulting output through another sed filter to remove the CGROUP column header: -

ps -o cgroup `ps -elf | sed 1d | awk '{print $4}'` | sed 1d

which is nice.

Note that, in the above example, I'm running the output of ps -elf | sed 1d | awk '{print $4}' as input into ps o cgroup using the back-tick symbol ( ` ) which normally gets GARBLED when one copies from browser to terminal session.

For reference, and I had to Google for this, here's the reason for the name AWK: -

...
Aho is also widely known for his co-authorship of the AWK programming language with Peter J. Weinberger and Brian Kernighan (the "A" stands for "Aho").
....


So, we have Aho + Weinberger + Kernighan which gives us AWK :-)


Thursday, 7 February 2019

New day, new job - more of the same, but in a VERY good way

Well, technically I started my new job yesterday - 6 February.

Well, to be more accurate, I've been morphing into my new job for the past few weeks.

Well, to be even more accurate, I'm still doing a bit of my old job, whilst also doing my new job.

Is that 100% clear ?

Anyway, after 10 years in IBM Software Services ( under different organisational names ) and nearly 20 years in IBM Software Group ( again under different organisations, most recently IBM Cloud ), I've changed roles.

From an IBM organisational perspective, I've gone back to my roots, as I'm now part of IBM Systems Group, which I joined way back in 1992 when I was working in AS/400 technical support.

Since then, I've worked with all of IBM's server range, including the since departed System X ( Intel-based X86 products moved to Lenovo back in 2014 ) .....

With one exception.

Whilst I've worked on AS/400 ( became iSeries, became System i, now IBM I ) and RS/6000 ( became pSeries, became System p, now IBM Power ) and the aforementioned PS/2 ( became Netfinity, System x and then departed ), I've never properly worked on S/390 ( which became zSeries, System z and now IBM Z ).

Well, I was an end-user of PROFS, EHONE, RETAIN etc. but that's not quite the same thing.

Apart from moving organisations, I've also moved into the IBM Development organisation for the first time ever. Having worked in support, ISV/partner enablement, technical sales and then software services, this is the first time I can honestly say .... I'm an IBM Developer.

Well, now I am.

Bringing the two together is where I'm at.

So after that lengthy introduction, what am I doing ?

Well, I've joined the IBM Hyper Protect Containers team, based in Hursley Park, also known as Z-as-a-Service (ZaaS) bringing Kubernetes to the IBM mainframe ( or vice versa ).

In the main, this means that I'm hands-on and knee-deep in coding, Agile and Design Thinking and test-driven development. It means that I'm going to be learning learning learning ...

Right now, I'm living in macOS Terminal, with SSH sessions, vi/sed/awk/grep, Bash scripting and, of course, Linux, Docker and Kubernetes.

So no change there then.

If you read my posts over the past few years, guess what I've been doing ... much the same, albeit more focused on the Intel x86-64 platforms.

I'm also getting to grips with GitHub, Jenkins, UrbanCode Deploy etc. which again builds upon what I've done before.

So, as ever throughout my long career ( in my 34th year ), it's career by evolution, taking what I know, and growing it .....

Or, to use my most common catch-phrase, #LifeIsGood

Watch this space.... more to follow

Wednesday, 6 February 2019

Fun and games with pushing Docker images to Kubernetes registry

I hit a wee problem today, whilst pushing a Docker image ( WebSphere Liberty Profile ) from my local Docker registry to the registry associated with my IBM Kubernetes Service (IKS) cluster.

For reference, I wrote about Liberty on Docker earlier: -

 WebSphere Liberty Profile on Docker - An update 

I'd tagged the image: -

docker tag websphere-liberty:latest registry.ng.bluemix.net/davehay42/wlp

and pushed it to the newly created IKS cluster registry: -

docker push registry.ng.bluemix.net/davehay42/wlp:latest

I validated that the image was there: -

ibmcloud cr image-list

...
Listing images...

REPOSITORY                                        TAG          DIGEST         NAMESPACE     CREATED       SIZE     SECURITY STATUS
registry.ng.bluemix.net/davehay42/davehay         helloworld   92c7f9c92844   davehay42     1 month ago   977 B    No Issues
registry.ng.bluemix.net/davehay42/wlp             latest       6631eaf721ad   davehay42     4 days ago    335 MB   No Issues
registry.ng.bluemix.net/dmh_k8s_poc/dmh_k8s_poc   hello        92c7f9c92844   dmh_k8s_poc   1 month ago   977 B    No Issues
...

and then created a K8S deployment: -

kubectl create deployment wlp --image=latest

Alas when I checked the pod to which the deployment was pushed: -

kubectl describe pod `kubectl get pods | grep wlp | awk '{print $1}'`

I saw this: -

...
  Type     Reason                 Age                From                   Message
  ----     ------                 ----               ----                   -------
  Normal   Scheduled              36s                default-scheduler      Successfully assigned wlp-598d758678-w4tj7 to 10.76.195.65
  Normal   SuccessfulMountVolume  36s                kubelet, 10.76.195.65  MountVolume.SetUp succeeded for volume "default-token-8znfb"
  Normal   Pulling                19s (x2 over 35s)  kubelet, 10.76.195.65  pulling image "a83fa38506a5"
  Warning  Failed                 18s (x2 over 34s)  kubelet, 10.76.195.65  Failed to pull image "a83fa38506a5": rpc error: code = Unknown desc = Error response from daemon: pull access denied for a83fa38506a5, repository does not exist or may require 'docker login'
  Warning  Failed                 18s (x2 over 34s)  kubelet, 10.76.195.65  Error: ErrImagePull
  Normal   BackOff                4s (x2 over 33s)   kubelet, 10.76.195.65  Back-off pulling image "a83fa38506a5"
  Warning  Failed                 4s (x2 over 33s)   kubelet, 10.76.195.65  Error: ImagePullBackOff
...

Thankfully, after reading this tutorial: -


This tutorial shows you how to run a simple Hello World Node.js app on Kubernetes using Minikube and Katacoda. Katacoda provides a free, in-browser Kubernetes environment.

I realised where I was going wrong ....

The image specified in the kubectl create deployment command was WAY too vague.

I deleted my deployment

kubectl delete deployment wlp

and then recreated it using the full tag ( registry/namespace/tag ): -

kubectl create deployment wlp --image=registry.ng.bluemix.net/davehay42/wlp

I was then able to validate the deployment: -

kubectl get deployments

NAME      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
wlp       1         1         1            1           16m

and validated the deployed pod: -

kubectl describe pod `kubectl get pods | grep wlp | awk '{print $1}'`

...
Events:
  Type    Reason                 Age   From                   Message
  ----    ------                 ----  ----                   -------
  Normal  Scheduled              17m   default-scheduler      Successfully assigned wlp-7865f8b77c-xlnf2 to 10.76.195.65
  Normal  SuccessfulMountVolume  17m   kubelet, 10.76.195.65  MountVolume.SetUp succeeded for volume "default-token-8znfb"
  Normal  Pulling                17m   kubelet, 10.76.195.65  pulling image "registry.ng.bluemix.net/davehay42/wlp"
  Normal  Pulled                 16m   kubelet, 10.76.195.65  Successfully pulled image "registry.ng.bluemix.net/davehay42/wlp"
  Normal  Created                16m   kubelet, 10.76.195.65  Created container
  Normal  Started                16m   kubelet, 10.76.195.65  Started container
...

I was then able to validate that Liberty was up-and-running: -

kubectl logs `kubectl get pods | grep wlp | awk '{print $1}'`

Launching defaultServer (WebSphere Application Server 19.0.0.1/wlp-1.0.24.cl190120190124-2339) on IBM J9 VM, version 8.0.5.27 - pxa6480sr5fp27-20190104_01(SR5 FP27) (en_US)
[AUDIT   ] CWWKE0001I: The server defaultServer has been launched.
[AUDIT   ] CWWKE0100I: This product is licensed for development, and limited production use. The full license terms can be viewed here: https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/wasdev/license/base_ilan/ilan/19.0.0.1/lafiles/en.html
[AUDIT   ] CWWKG0093A: Processing configuration drop-ins resource: /opt/ibm/wlp/usr/servers/defaultServer/configDropins/defaults/keystore.xml
[WARNING ] CWWKS3103W: There are no users defined for the BasicRegistry configuration of ID com.ibm.ws.security.registry.basic.config[basic].
[AUDIT   ] CWWKZ0058I: Monitoring dropins for applications.
[AUDIT   ] CWWKS4104A: LTPA keys created in 1.268 seconds. LTPA key file: /opt/ibm/wlp/output/defaultServer/resources/security/ltpa.keys
[AUDIT   ] CWPKI0803A: SSL certificate created in 2.690 seconds. SSL key file: /opt/ibm/wlp/output/defaultServer/resources/security/key.jks
[AUDIT   ] CWWKI0001I: The CORBA name server is now available at corbaloc:iiop:localhost:2809/NameService.
[AUDIT   ] CWWKF0012I: The server installed the following features: [beanValidation-2.0, servlet-4.0, ssl-1.0, jndi-1.0, jca-1.7, cdi-2.0, jdbc-4.2, jms-2.0, ejbPersistentTimer-3.2, appSecurity-3.0, appSecurity-2.0, j2eeManagement-1.1, wasJmsServer-1.0, javaMail-1.6, jaxrs-2.1, webProfile-8.0, jpa-2.2, jcaInboundSecurity-1.0, jsp-2.3, jsonb-1.0, ejbLite-3.2, managedBeans-1.0, jsf-2.3, ejbHome-3.2, jaxws-2.2, jsonp-1.1, jaxrsClient-2.1, el-3.0, concurrent-1.0, appClientSupport-1.0, ejbRemote-3.2, jaxb-2.2, mdb-3.2, jacc-1.5, javaee-8.0, batch-1.0, ejb-3.2, jpaContainer-2.2, jaspic-1.1, distributedMap-1.0, websocket-1.1, wasJmsSecurity-1.0, wasJmsClient-2.0].
[AUDIT   ] CWWKF0011I: The server defaultServer is ready to run a smarter planet.

which is a good sign.

I could then open a command prompt ( shell ) on the WLP container within the pod: -

kubectl exec -i -t `kubectl get pods | grep wlp | awk '{print $1}'` /bin/bash

default@wlp-7865f8b77c-xlnf2:/$ 

and run a WLP command: -

/opt/ibm/wlp/bin/server version

WebSphere Application Server 19.0.0.1 (1.0.24.cl190120190124-2339) on IBM J9 VM, version 8.0.5.27 - pxa6480sr5fp27-20190104_01(SR5 FP27) (en_US)

and examine the WLP server.xml file: -

cat /opt/ibm/wlp/usr/servers/defaultServer/server.xml 


   
   
        javaee-8.0
   

   
    
   
   
    
   
     
         
   
    
   
   
                  host="*"
 httpPort="9080"
                  httpsPort="9443" />
                  
   
   


This means that we have a pod deployed, hosting the WebSphere Liberty Profile container, and that WLP is looking clean-and-green.

I then used kubectl cp to copy a JEE web application ( Ferret ) into the WLP container in the pod: -

kubectl cp /tmp/ferret-1.2.war `kubectl get pods | grep wlp | awk '{print $1}'`:/opt/ibm/wlp/usr/servers/defaultServer/dropins/

and validated that it started: -

kubectl logs `kubectl get pods | grep wlp | awk '{print $1}'`

....
[AUDIT   ] CWWKF0011I: The server defaultServer is ready to run a smarter planet.
[AUDIT   ] CWWKT0016I: Web application available (default_host): http://wlp-7865f8b77c-xlnf2:9080/ferret/
[AUDIT   ] CWWKZ0001I: Application ferret-1.2 started in 1.414 seconds.
...

I then created a nodeport service: -

kubectl create service nodeport wlp --tcp=80:9080

and retrieved the node details: -

kubectl describe node `kubectl get nodes | grep -i iks|awk '{print $1}'`
...
Addresses:
  InternalIP:  10.76.195.65
  ExternalIP:  173.193.82.117
  Hostname:    10.76.195.65
...

and the newly created nodeport service: -

kubectl get services

...
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   172.21.0.1              443/TCP        1h
wlp          NodePort    172.21.67.96          80:31135/TCP   23m
...

Using the combination of the external IP ( 173.193.82.117 ) and the generated node port ( 31135 ), I was then able to access Liberty: -

http://173.193.82.117:31135/


AND the Ferret application: -

http://173.193.82.117:31135/ferret/


So, to summarise, we've taken a Docker image from the official repo ( https://hub.docker.com/_/websphere-liberty ), tagged it to make unique to us, pushed it to a newly created IBM Kubernetes Service (IKS) cluster, created a deployment ( deploying the container to a pod on a node ), created a service to expose the Liberty server's port 9080, and accessed Liberty via the web UI.

We also showed how one can use kubectl cp and kubectl exec to access the internals of the running container, similar to the way that docker cp and docker exec work.

Nice.

WebSphere Liberty Profile on Docker - An update

In the context of my current project, we were talking about running WebSphere Liberty Profile on Docker, so here's an update: -

Pull Liberty Docker Image

docker pull websphere-liberty

Using default tag: latest
latest: Pulling from library/websphere-liberty
7b722c1070cd: Pull complete 
5fbf74db61f1: Pull complete 
ed41cb72e5c9: Pull complete 
7ea47a67709e: Pull complete 
449210cbff3b: Pull complete 
18c9d73c43bb: Pull complete 
34afdf15398d: Pull complete 
83a69d4d0146: Pull complete 
bb817bf5c90c: Pull complete 
ebb9f104335d: Pull complete 
7714cd589690: Pull complete 
d5191570a227: Pull complete 
79c80066476d: Pull complete 
acf01b72e712: Pull complete 
c9445dae1684: Pull complete 
Digest: sha256:fa2aaccc861c66fa20c8d6f67b8913b10517e6e441d2420d525e591b718c2e77
Status: Downloaded newer image for websphere-liberty:latest

Validate the image

docker images

REPOSITORY                                  TAG                 IMAGE ID            CREATED             SIZE
websphere-liberty                           latest              a83fa38506a5        4 days ago          585MB
hello-world                                 latest              fce289e99eb9        5 weeks ago         1.84kB
registry.ng.bluemix.net/davehay42/davehay   helloworld          fce289e99eb9        5 weeks ago         1.84kB

Start a container

- Note that we're using the -v ( aka --volumes ) switch to make a local WAR file available to the container
- Note that we're also mapping ports using -p and running the container as a daemon ( -d )

docker run -d -p 80:9080 -p 443:9443 -v /tmp/ferret-1.2.war:/config/dropins/ferret-1.2.war websphere-liberty:latest

4823dd0bc7a690a1ae6eafce6a0a8611fdf4cc73f6beadd6436c67c1a4838231

- Note that the container ID is in full; the short version is 4823dd0bc7a6 as will be seen later using docker ps -a

Check the container logs

docker logs 4823dd0bc7a690a1ae6eafce6a0a8611fdf4cc73f6beadd6436c67c1a4838231

Launching defaultServer (WebSphere Application Server 19.0.0.1/wlp-1.0.24.cl190120190124-2339) on IBM J9 VM, version 8.0.5.27 - pxa6480sr5fp27-20190104_01(SR5 FP27) (en_US)
[AUDIT   ] CWWKE0001I: The server defaultServer has been launched.
[AUDIT   ] CWWKE0100I: This product is licensed for development, and limited production use. The full license terms can be viewed here: https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/wasdev/license/base_ilan/ilan/19.0.0.1/lafiles/en.html
[AUDIT   ] CWWKG0093A: Processing configuration drop-ins resource: /opt/ibm/wlp/usr/servers/defaultServer/configDropins/defaults/keystore.xml
[WARNING ] CWWKS3103W: There are no users defined for the BasicRegistry configuration of ID com.ibm.ws.security.registry.basic.config[basic].
[AUDIT   ] CWWKZ0058I: Monitoring dropins for applications.
[AUDIT   ] CWWKS4104A: LTPA keys created in 0.650 seconds. LTPA key file: /opt/ibm/wlp/output/defaultServer/resources/security/ltpa.keys
[AUDIT   ] CWPKI0803A: SSL certificate created in 2.125 seconds. SSL key file: /opt/ibm/wlp/output/defaultServer/resources/security/key.jks
[AUDIT   ] CWWKI0001I: The CORBA name server is now available at corbaloc:iiop:localhost:2809/NameService.
[AUDIT   ] CWWKT0016I: Web application available (default_host): http://4823dd0bc7a6:9080/ferret/
[AUDIT   ] CWWKZ0001I: Application ferret-1.2 started in 0.725 seconds.
[AUDIT   ] CWWKF0012I: The server installed the following features: [beanValidation-2.0, servlet-4.0, ssl-1.0, jndi-1.0, jca-1.7, cdi-2.0, jdbc-4.2, jms-2.0, ejbPersistentTimer-3.2, appSecurity-3.0, appSecurity-2.0, j2eeManagement-1.1, wasJmsServer-1.0, javaMail-1.6, jaxrs-2.1, webProfile-8.0, jpa-2.2, jcaInboundSecurity-1.0, jsp-2.3, jsonb-1.0, ejbLite-3.2, managedBeans-1.0, jsf-2.3, ejbHome-3.2, jaxws-2.2, jsonp-1.1, jaxrsClient-2.1, el-3.0, concurrent-1.0, appClientSupport-1.0, ejbRemote-3.2, jaxb-2.2, mdb-3.2, jacc-1.5, javaee-8.0, batch-1.0, ejb-3.2, jpaContainer-2.2, jaspic-1.1, distributedMap-1.0, websocket-1.1, wasJmsSecurity-1.0, wasJmsClient-2.0].
[AUDIT   ] CWWKF0011I: The server defaultServer is ready to run a smarter planet.

Test the Ferret app using cURL

curl http://localhost/ferret/

Test the Ferret app using a real browser



Look at the running Docker container(s)

docker ps -a

CONTAINER ID        IMAGE                      COMMAND                  CREATED             STATUS                         PORTS                                         NAMES
4823dd0bc7a6        websphere-liberty:latest   "/opt/ibm/helpers/ru…"   22 minutes ago      Up 22 minutes                  0.0.0.0:80->9080/tcp, 0.0.0.0:443->9443/tcp   keen_torvalds
3d8899de8f32        hello-world                "/hello"                 About an hour ago   Exited (0) About an hour ago                                                 happy_colden

Open a shell to the container

docker exec -i -t 4823dd0bc7a6 /bin/bash

default@4823dd0bc7a6:/$ 

Examine the detailed Liberty messages

default@4823dd0bc7a6:/$ cat logs/messages.log 

Check the Liberty version

default@4823dd0bc7a6:/$ /opt/ibm/wlp/bin/server version

WebSphere Application Server 19.0.0.1 (1.0.24.cl190120190124-2339) on IBM J9 VM, version 8.0.5.27 - pxa6480sr5fp27-20190104_01(SR5 FP27) (en_US)

Exit the shell

default@4823dd0bc7a6:/$ exit

Stop the container

docker stop 4823dd0bc7a6

4823dd0bc7a6

Remove the container

docker rm 4823dd0bc7a6

4823dd0bc7a6

Thanks to this: -

Official IBM WebSphere Application Server for Developers Liberty image.

for inspiration.

Note to self - Firefox and local connections

 Whilst trying to hit my NAS from Firefox on my Mac, I kept seeing errors such as:- Unable to connect Firefox can’t establish a connection t...