Article
· Apr 18, 2025 3m read

Mini Tip of the Day - Preloading the License into the Docker IRIS Image

Who hasn't been developing a beautiful example using a Docker IRIS image and had the image generation process fail in the Dockerfile because the license under which the image was created doesn't contain certain privileges?

In my case, what I was deploying in Docker is a small application that uses the Vector data type. With the Community version, this isn't a problem because it already includes Vector Search and vector storage. However, when I changed the IRIS image to a conventional IRIS (the latest-cd), I found that when I built the image, including the classes it had generated, it returned this error:

9.505 ERROR #15806: Vector Search not permitted with current license
9.505   > ERROR #5030: An error occurred while compiling class 'Inquisidor.Object.LicitacionOS'
9.505 Compiling class Inquisidor.Object.Licitacion
9.505 ERROR #15806: Vector Search not permitted with current license
9.505   > ERROR #5030: An error occurred while compiling class 'Inquisidor.Object.Licitacion'
9.538 Compiling class Inquisidor.Message.LicitacionResponse

This error left me confused, because I, as an obedient person, had defined in my docker-compose.yml the parameter that indicates where my valid license is located:

  iris:
    init: true
    container_name: iris
    build:
      context: .
      dockerfile: iris/Dockerfile
    ports:
      - 52774:52773
      - 51774:1972
    volumes:
    - ./iris/shared:/iris-shared
    environment:
    - ISC_DATA_DIRECTORY=/iris-shared/durable
    command: --check-caps false --ISCAgent false --key /iris-shared/iris.key

It took me a while to realize that the problem was the original image I was using, not the license I had, as you can see, I'm not the sharpest pencil in the case.

The problem was at the point where I imported my classes into the default IRIS image:

RUN \
zn "%SYS" \
do ##class(SYS.Container).QuiesceForBundling() \
do ##class(Security.Users).UnExpireUserPasswords("*") \
set sc=##class(%SYSTEM.OBJ).Load("/opt/irisapp/DemoSetup.Utilities.cls","ck") \
set helper=##class(DemoSetup.Utilities).%New() \ 
do helper.EnableSSLSuperServer() \
do ##class(Security.Applications).Import("/ApplicationInquisidor.xml",.n) \
zn "INQUISIDOR" \
set sc = $SYSTEM.OBJ.LoadDir("/opt/irisapp/src/Inquisidor", "ck", , 1) \
set production = "Inquisidor.Production" \
set ^Ens.Configuration("csp","LastProduction") = production \
do ##class(Ens.Director).SetAutoStart(production) \

Compiling the code was returning the previous error. What should I do to fix it? It was very simple: I had to send the new license to the initial IRIS image and ask it to update the license on the first line of the commands I was using.

The first step is to move the new license to the /mgr  directory of the installation, which I did with this code:

COPY --chown=$ISC_PACKAGE_MGRUSER:$ISC_PACKAGE_IRISGROUP /iris/iris.key /usr/irissys/mgr
RUN chmod +x /usr/irissys/mgr/iris.key

The IRIS installation path on our image is  /usr/irissys/mgr , and the /iris/iris.key path is my local directory. With the license in the IRIS image, I just needed to tell IRIS to update its license, so I modified the previous commands by adding the following statement:

RUN \
zn "%SYS" \
do ##class(%SYSTEM.License).Upgrade() \

 Et voila! I now have my IRIS image with my license loaded before importing and compiling my classes. No more compilation errors.

I hope it is useful to you!

Discussion (6)1
Log in or sign up to continue

Hi Luiz,  yes - I ran into this too and implemented a similar approach, however - the last thing I do is then remove the license key from the image.

This is because I do not want (in my case at least), to build images which hold valid keys.  Especially if posting this the image to a public registry.

I would expect consumers of the image would bring their own license key.

important note

When you add something and delete during build with Dockerfile, you should remember how docker build works, and do it in one RUN line, if you do COPY/ADD file then delete it in RUN, it will not delete file from the image, it will hide it in the final image. Due to layered nature of Docker images, COPY/ADD/RUN are separated layers, and generates a difference between. So, file still can be exctrated. 

And nowdays, the best approach to using binding in RUN

....

RUN \
  --mount=type=bind,src=.,dst=/opt/app \
  cp /opt/app/iris.key /usr/irissys/mgr/iris.key && \
  iris start IRIS && \
  ....
  iris stop IRIS quietly && \
  rm -f /usr/irissys/mgr/iris.key

or you can mount it straight to the way where it's expected, and it will not stay in the final image

...

RUN --mount=type=bind,src=/iris.key,dst=/usr/irissys/mgr/iris.key \
    iris start IRIS && \
    /bin/echo -e 'do ##class(%SYSTEM.License).CKEY() halt' | iris session IRIS -U %SYS && \
    iris stop IRIS quietly