This is intentional behavior.
If the routine you changed calls some subroutine it is kept "on the stack"
This is a requirement to have a save return and continuation after the call.

The new version only becomes active after you have left the previous one by QUIT or RETURN.
simpler: if it is gone from the return path. 

You may have only 1 command: in each build
the 2nd overwrites the first

  iris:
    image: intersystemsdc/iris-community:latest
    command: --check-caps false
    container_name: tls-ssl-iris
    networks:
      app_net:
        ipv4_address: 172.16.238.20
    volumes:
      - ./iris-config-files:/opt/config-files
      # Mount certificates files.
      - ./certificates/CA_Server.cer:/usr/irissys/mgr/CA_Server.cer
      - ./certificates/iris_server.cer:/usr/irissys/mgr/iris_server.cer
      - ./certificates/iris_server.key:/usr/irissys/mgr/iris_server.key
    hostname: iris
    # Load the IRIS configuration file ./iris-config-files/iris-config.json
    command: ["-a","sh /opt/config-files/configureIris.sh"] 

this worked as multi-line 

command: 
    - -a
    - sh /opt/config-files/configureIris.sh 
      - --check-caps false

BUT  
         command: ["-a","sh /opt/config-files/configureIris.sh","--check-caps false"]

works as well 
 

in my package GlobalToJSON-ePython-pure
I developed this workaround: 

#; simulate $data() for existence and content
def Ddata(gref):
	val = None
	_d = 11
#; check for subscripts	
	o=gref.order([])
	if o == None:
		_d -= 10
	try:
		val=gref.get([])
	except KeyError:
		#; no value @ top node
		_d -= 1
	return [_d,val]		

The actual GTY is containers.intersystems.com/intersystems/webgateway:2022.1.0.209.0

And there is no :latest defined
 

You may use input redirection as you find it in almost all Dockerfile installations:
 

RUN iris start IRIS \
    && iris session IRIS < iris.script \
    && iris stop IRIS quietly 

and iris.script (as example)


zn "%SYS"
Do ##class(Security.Users).UnExpireUserPasswords("*")
zn "USER"

 

Class Reference of %SYSTEM.Status says:
classMethode IsError(statuscode As %Status) as %Boolean

Returns 1 if the statuscode contains errors. Otherwise, it returns 0.

 So if you get  [res] as  (0,....)  it is an ERROR!  
and therefore the result of IsError should be 1.  It is an Error.

%BI classes date back to Miner (DeepSee-1) and just were left in Caché over a decade at least
while its functionality was replaced by %DeepSee classes more than 10 years ago.

Of course, you can map all %BI.*  classes to some DB where you have R/W access and import it from Caché.
that's about 300 Classes.
BUT:  no one can tell you if they compile correctly
AND: you have to take care of the hidden %bi*.obj (~430) and other deployed code which you can't compile, but import and pray they work.

SO: this doesn't look like a  promising approach.

Therefore I'd suggest migrating from %BI to %DeepSee in Caché first and to IRIS next

just to make your valuable entry visible in browser and email
http://<server-ip>:<smp-port>/api/atelier/
and you get back this nice JSON object: