Building an Image
Although it is recommended to use extension packages to bundle up additional applications needed by workshops, and overlay those on the standard workshop base image when a workshop session is started, it is possible to build your own custom workshop base images. Because this results in a hard dependency on a specific version of the workshop base image, it can result in workshop images which may not work with a newer Educates version. As such, only use this ability if you feel there is no other choice.
Structure of the Dockerfile
The structure of the Dockerfile
to build a custom workshop base image should start out as:
FROM ghcr.io/vmware-tanzu-labs/educates-base-environment:2.6
COPY --chown=1001:0 . /home/eduk8s/
RUN mv /home/eduk8s/workshop /opt/workshop
RUN fix-permissions /home/eduk8s
A custom workshop image needs to be built on the ghcr.io/vmware-tanzu-labs/educates/base-environment
workshop image.
Where the custom workshop image will also include files for a specific workshop, the default actions you include when building the container image should include copying all files to the /home/eduk8s
directory. The --chown=1001:0
option ensures that files are owned by the appropriate user and group. The workshop
subdirectory is then moved to /opt/workshop
so that it is out of the way and not visible to the user. This is a special location which will be searched for workshop content, in addition to /home/eduk8s/workshop
. To have other files or directories from the repository ignored, list them in the .dockerignore
file.
It is possible to include RUN
statements in the Dockerfile
to run custom build steps, but the USER
inherited from the base image will be that having user ID 1001
and will not be the root
user.
Custom workshop base images
The base-environment
workshop images include language run times for Node.js and Python. If you need a different language runtime, or need a different version of a language runtime, you will need to use a custom workshop base image which includes the supported environment you need. This custom workshop image would be derived from base-environment
but include the extra runtime components needed.
For using the Java programming language, the Educates project provides separate custom workshop images for JDK 8, 11 and 17. In addition to including the respective Java runtimes, they include Gradle and Maven.
The name of the JDK 8 version of the Java custom workshop base image is:
ghcr.io/vmware-tanzu-labs/educates-jdk8-environment:2.6
To see what specific tagged version of the image exist visit:
The name of the JDK 11 version of the Java custom workshop base image is:
ghcr.io/vmware-tanzu-labs/educates-jdk11-environment:2.6
To see what specific tagged version of the image exist visit:
The name of the JDK 17 version of the Java custom workshop base image is:
ghcr.io/vmware-tanzu-labs/educates-jdk17-environment:2.6
To see what specific tagged version of the image exist visit:
The name of the JDK 21 version of the Java custom workshop base image is:
ghcr.io/vmware-tanzu-labs/educates-jdk21-environment:2.6
To see what specific tagged version of the image exist visit:
The images will be updated over time to try and include the latest versions of Gradle and Maven. In case you are using Gradle or Maven wrapper scripts for selecting a specific version of these tools, configuration for these wrapper scripts is provided for the pre-installed version to avoid it being downloaded again.
If wanting to run workshops based around using Anaconda Python or Jupyter notebooks, the Educates project provides a suitable base environment.
The name of the Anaconda workshop base image is:
ghcr.io/vmware-tanzu-labs/educates-conda-environment:2.6
To see what specific tagged version of the image exist visit:
Container run as random user ID
It is assumed that when a workshop is run, the container is run as the user 1001
that the workshop base image has set. This will be the case when a typical Kubernetes distribution is used, but some Kubernetes distributions such as OpenShift, may enforce a pod security policy (or security context constraint) which forces pods in distinct namespaces to run as different assigned user IDs, overriding the default.
This can cause a problem if the workshop requires a user to run steps that need to write to the file system under /home/eduk8s
, and the location to be written to is a file copied into the image, or a sub directory. This is because the assigned user ID will not have the permissions to write to the files or directory.
To cope with this, a setup script called fix-permissions
is included in the base image and is executed as the final step from the Dockerfile
. This command will ensure that group permissions for all files and directories are the same as the user permissions. This will allow group write access to work for the user the container image would be run as when not the intended user.
Note that this is only an issue if you wish to create workshop content that you want people to be able to run on a Kubernetes distribution such as OpenShift, which has a strict security policy which forces containers to run as a user ID different to what the container image specifies.
Note that this OpenShift issue may no longer exist due to changes in Educates, but is good practice all the same.
Installing extra system packages
Installation of extra system packages requires the installation to be run as root
. To do this you will need to switch the user commands are run as before running the command. You should then switch the user back to user ID of 1001
when done.
USER root
RUN ... commands to install system packages
USER 1001
It is recommended you only use the root
user to install extra system packages. Don’t use the root
user when adding anything under /home/eduk8s
. If you do you will need to ensure the user ID and group for directories and files are set to 1001:0
and then run the fix-permissions
command if necessary.
One problem you should guard against though is that when running any command as root
, you should temporarily override the value of the HOME
environment variable and set it to /root
.
If you don’t do this, because the HOME
environment variable is by default set to /home/eduk8s
, the root
user may drop configuration files in /home/eduk8s
, thinking it is the root
home directory. This can cause commands run later during the workshop to fail, if they try and update the same configuration files, as they will have wrong permissions.
Fixing the file and group ownership and running fix-permissions
may help with this problem, but not always because of the strange permissions the root
user may apply and how container image layers work. It is therefore recommended instead to always use:
USER root
RUN HOME=/root && \
... commands to install system packages
USER 1001
Installing third party packages
If you are not using system packaging tools to install extra packages, but are instead manually downloading packages, and optionally compiling them to binaries, it is better to do this as the default user and not root
.
If compiling packages, it is recommended to always work in a temporary directory under /tmp
and to remove the directory as part of the same RUN
statement when done.
If what is being installed is just a binary, it can be installed into the /home/eduk8s/bin
. This directory is automatically in the application search path defined by the PATH
environment variable for the image.
If you need to install a whole directory hierarchy of files, create a separate directory under /opt
to install everything. You can then override the PATH
environment variable in the Dockerfile
to add any extra directory for application binaries and scripts, and the LD_LIBRARY_PATH
environment variable for the location of shared libraries.
If installing any files from a RUN
instruction into /home/eduk8s
, it is recommended you run fix-permissions
as part of the same instruction to avoid copies of files being made into a new layer, which would be the case if fix-permissions
is only run in a later RUN
instruction. You can still leave the final RUN
instruction for fix-permissions
as it is smart enough not to apply changes if the file permissions are already set correctly, and so it will not trigger a copy of a file when run more than once.