Run a sample standalone app under docker.
ssh into your group’s host server, and switch to the “root” user:
$ sudo -s
#
Keycloak is a fairly complex application to build and install (it depends on Java). Here we’ll show how easy it is to get up and running in a docker container.
Because it’s a networked application, we’ll need to enabling forwarding of traffic on a TCP port to reach it.
Run the following command:
# docker run -p 8443:8443 -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin --name keycloak quay.io/keycloak/keycloak:15.0.2
You should find the application startup logs written to the console. While that happens, here’s an explanation of the flags:
-p 8443:8443: accept connections on port 8443 on the host, and forward them to port 8443 on the container. How do we know the container listens on port 8443? The container author has to document this!-e VAR=VALUE: set environmen variable VAR to VALUE. This is used to pass settings to the container. Again, to know which settings a given container understands, you need to look in its documentation.--name keycloak: assign a name to the container, to prevent docker choosing a random name like “eloquent_kapitsa”After a few seconds it will finish initializing:
...
19:12:32,983 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: Keycloak 15.0.2 (WildFly Core 15.0.1.Final) started in 12048ms - Started 692 of 977 services (686 services are lazy, passive or on-demand)
19:12:32,984 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0060: Http management interface listening on http://127.0.0.1:9990/management
19:12:32,984 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0051: Admin console listening on http://127.0.0.1:9990
Now point your web browser at port 8443 on your own host, with HTTPS:
https://hostX.ws.nsrc.org:8443/
Accept the self-signed certificate. Click on “Administration Console”. Login as “admin” and “admin”. You have a running keycloak server!
Go back to where you see the console logs. Stop the container by hitting ctrl-C. This should return you back to the shell prompt.
...
19:27:33,880 INFO [org.infinispan.CLUSTER] (ServerService Thread Pool -- 78) ISPN000080: Disconnecting JGroups channel ejb
19:27:33,891 INFO [org.jboss.as] (MSC service thread 1-2) WFLYSRV0050: Keycloak 15.0.2 (WildFly Core 15.0.1.Final) stopped in 72ms
*** JBossAS process (201) received TERM signal ***
root@hostX:~#
Now try running the container again using the exact same command. What happens this time?
# docker run -p 8443:8443 -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin --name keycloak quay.io/keycloak/keycloak:15.0.2
docker: Error response from daemon: Conflict. The container name "/keycloak" is already in use by container "7cf852e94fc60fd480bdb474f17e4235c90517fa151a8ebf7f1828c9712179e0". You have to remove (or rename) that container to be able to reuse that name.
See 'docker run --help'.
What you’re trying to do is to create a new container with name “keycloak”. But you already have a container called “keycloak” (even though it’s stopped). You can see it like this:
root@s1:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7cf852e94fc6 quay.io/keycloak/keycloak:15.0.2 "/opt/jboss/tools/do…" 8 minutes ago Exited (0) 2 minutes ago keycloak
So what can you do now? You can simply restart the existing container:
# docker start keycloak
keycloak
This time, keycloak has started in the background - it’s returned straight back to the shell, and you can’t see the console logs it generates.
Those logs are still visible using the “docker logs” command:
# docker logs keycloak
...
19:30:40,111 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: Keycloak 15.0.2 (WildFly Core 15.0.1.Final) started in 9812ms - Started 692 of 977 services (686 services are lazy, passive or on-demand)
19:30:40,112 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0060: Http management interface listening on http://127.0.0.1:9990/management
19:30:40,112 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0051: Admin console listening on http://127.0.0.1:9990
That’s all good.
Now let’s try running a second instance of keycloak. To do this we need to make a few things different:
-d flag (for “daemon”)# docker run -d -p 9443:8443 -e KEYCLOAK_USER=nsrc -e KEYCLOAK_PASSWORD=nsrc --name keycloak2 quay.io/keycloak/keycloak:15.0.2
0705359be2b9e84c96fb97922c00c29172a12714eff2c5b4d80b927bd3aa5704
#
This time it just prints the container ID (yours will be different) and returns to the shell. You can see both instances running:
# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0705359be2b9 quay.io/keycloak/keycloak:15.0.2 "/opt/jboss/tools/do…" 47 seconds ago Up 46 seconds 8080/tcp, 0.0.0.0:9443->8443/tcp, :::9443->8443/tcp keycloak2
7cf852e94fc6 quay.io/keycloak/keycloak:15.0.2 "/opt/jboss/tools/do…" 21 minutes ago Up 56 seconds 8080/tcp, 0.0.0.0:8443->8443/tcp, :::8443->8443/tcp keycloak
Now point your web browser at port 9443 on your own host, with HTTPS:
https://hostX.ws.nsrc.org:9443/
Once again, accept the self-signed certificate. Click on “Administration Console”. This time you’ll have to login as “nsrc” and “nsrc”.
You should note that we have two containers, but they were both started from the same published container image (keycloak).
It’s often possible to get a shell inside a running container, and this can be useful for debugging. Try the following:
# docker exec -it keycloak bash
bash-4.4$ hostname
44c432836df5
bash-4.4$ ps auxwww
bash: ps: command not found
The good news: there is a bash shell available in the container, and we can run it. Note that the container has its own “hostname” (which is the container ID), separate from the system hostname.
The bad news: many containers have a very cut-down environment with few utilities. In this case, even the most basic “ps” utility is missing.
We can have a look at what is in the /bin directory:
bash-4.4$ ls /bin
'[' cp domainname .... etc
To look at process information, we may need to get creative. The kernel exposes its list of processes under a directory called /proc, which we can list:
bash-4.4$ ls /proc
1 asound consoles dma fs kallsyms kpagecgroup mdstat mtrr sched_debug softirqs sysvipc version
201 buddyinfo cpuinfo driver interrupts kcore kpagecount meminfo net schedstat stat thread-self version_signature
456 bus crypto execdomains iomem keys kpageflags misc pagetypeinfo scsi swaps timer_list vmallocinfo
471 cgroups devices fb ioports key-users loadavg modules partitions self sys tty vmstat
acpi cmdline diskstats filesystems irq kmsg locks mounts pressure slabinfo sysrq-trigger uptime zoneinfo
You won’t see exactly the same as this. But notice the numeric entries:
These are processes, each with its own PID. We can only see the processes inside this container.
PID 1 is the process which was started when the container started, so is normally the application process. We can check this:
bash-4.4$ cat /proc/1/cmdline
/bin/sh/opt/jboss/keycloak/bin/standalone.sh-Djboss.bind.address=172.17.0.3-Djboss.bind.address.private=172.17.0.3-c=standalone-ha.xml-b0.0.0.0
Yes, you can see that this is some script for running keycloak, together with some flags like -D jboss.bind.address172.17.0.3 (in this view, all the arguments are squashed together without spaces)
That script has spawned its own child process - in this case it’s 201 but yours may be different - which is the actual java process that runs the application.
bash-4.4$ cat /proc/201/cmdline
java-D[Standalone]-server-Xms64m-Xmx512m-XX:MetaspaceSize=96M-XX:MaxMetaspaceSize=256m...
Process 456 here is the bash shell we started, and process 471 was the ls command that we typed (and has now gone). Again, the pids you see will be different, except pid 1.
Now exit the shell, by typing:
exit
Now, suppose a new version of keycloak comes out in future, say 15.0.3. How would you upgrade it?
The answer may be very surprising. You simply destroy the old container, and start a new container from the new image. You never login to a container and perform upgrades inside the container!
However, this presents a problem. What happens to all the data which was written by the application inside the container? That will be lost.
There are two solutions here.
The first is to make the application “stateless” - so it doesn’t keep any important local data at all. It could, for example, connect to a database over the network, and store all its state in the database. (This is the recommended way to run keycloak in production).
The other option is to mount a “docker volume” inside the container. The docker volume is a subdirectory which persists even when the container is destroyed, and can be mounted in a new container.
To do this, you need to know which subdirectory within the container needs to be preserved. Again, you need to look at the container documentation.
Keycloak makes this hard to find (because they prefer that you use an external database), but it’s /opt/jboss/keycloak/standalone/data
So let’s start again. First, stop and destroy both the existing containers.
# docker stop keycloak keycloak2
# docker rm keycloak keycloak2
Now we’ll create a docker volume called keycloak-data
# docker volume create keycloak-data
keycloak-data
Now start keycloak again, in the background (-d), and this time with the volume attached:
# docker run -d -p 8443:8443 -v keycloak-data:/opt/jboss/keycloak/standalone/data -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin --name keycloak quay.io/keycloak/keycloak:15.0.2
Now we are safe. Whenever the application in the container writes files underneath /opt/jboss/keycloak/standalone/data then those files will go in the docker volume. To upgrade the application, you can delete the container and recreate with the same volume attached.
Do you want to test this?
We now have some state.
Stop and destroy the container:
# docker stop keycloak
# docker rm keycloak
Recreate it, attached to the same docker volume as before:
# docker run -d -p 8443:8443 -v keycloak-data:/opt/jboss/keycloak/standalone/data -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin --name keycloak quay.io/keycloak/keycloak:15.0.2
Go back into the web interface, and look at the realms section. Does it still have a realm called “Workshop”? It should!
You can keep track of your docker volumes using docker volume list:
# docker volume list
DRIVER VOLUME NAME
local keycloak-data
You can see the images which have been downloaded to your system:
# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
quay.io/keycloak/keycloak 15.0.2 bd845c0bf911 4 weeks ago 714MB
This image is quite large. You can try removing it, but it will fail because there are containers which are still using it:
# docker rmi quay.io/keycloak/keycloak:15.0.2
Error response from daemon: conflict: unable to remove repository reference "quay.io/keycloak/keycloak:15.0.2" (must force) - container 7cf852e94fc6 is using its referenced image bd845c0bf911
Now stop the keycloak container with docker stop:
# docker stop keycloak
keycloak
# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7cf852e94fc6 quay.io/keycloak/keycloak:15.0.2 "/opt/jboss/tools/do…" 27 minutes ago Exited (0) 12 seconds ago keycloak
#
Even though it is stopped, the container is still using this image (it has a storage layer on top of this image). So to tidy up, you need to delete the container:
# docker rm keycloak
keycloak
Now you can delete the container image:
# docker rmi quay.io/keycloak/keycloak:15.0.2
Untagged: quay.io/keycloak/keycloak:15.0.2
Untagged: quay.io/keycloak/keycloak@sha256:b4a1ec2d93477ef32587bb29932e9567f967919a0a2d6cd54748060f90180b35
Deleted: sha256:bd845c0bf91114a6ebf2191a43cdcd1169f6fa81c7ff460ea3b178feeb9efbb9
Deleted: sha256:ee0c8020741cdff7c661563b3050b06350cac280468952b4472409271199673a
Deleted: sha256:2293744a3098b8ff5848d516ac1f65709af1b1e7646e54879328a4749487eb33
Deleted: sha256:ad7212ce593bbb61f246a3bef35dc4921cd244b7a6268c658bf59093f01a2cb3
Deleted: sha256:47c47b6fcf0b7a328bb5fc7bf9b66533702a0d345fa823c6107d3d2dc707a6b1
Deleted: sha256:54e42005468d41c980a6b5ec99544b942f856c6268750a09a5c4f1ed1226cf42
(You can see that the container image itself consisted of multiple layers)
In practice, you don’t have to delete unused images manually like this all the time. There is a special command docker image prune which removes all images that aren’t used by any containers. You can run it occasionally to reclaim storage space.