Symptom
You launched an OCI container instance and one of these happened:
- The instance goes from
CREATINGtoFAILED. - The instance is
ACTIVE, but a container keeps exiting and restarting. - The instance went
INACTIVEon its own. - Everything shows
ACTIVE, but nobody can reach the app on its port.
Match what you see to the likely cause:
| What you see | Likely cause | Go to |
|---|---|---|
FAILED during create, private OCIR image | No resource-principal policy to read the repo | Step 2 |
FAILED during create, Docker Hub or other external registry | No route to the internet, or missing or wrong pull secret | Steps 2-3 |
FAILED, image is very large | Image can't be unpacked in ephemeral storage | Step 4 |
FAILED, File Storage volume configured | Mount target not reachable from the subnet | Step 3 |
ACTIVE, container restarting | App crashes or its command is wrong; restart policy is Always | Step 5 |
INACTIVE | All containers exited and the restart policy doesn't restart them | Step 5 |
ACTIVE and healthy, app unreachable | NSG or security list doesn't allow the app port | Step 6 |
Note
FAILEDis a final state. You can't restart a failed container instance. Fix the cause and create a new one. Stopped and failed instances still count toward your service limits until you delete them.
1. Get the state and the error
C=ocid1.compartment.oc1..xxxx
oci container-instances container-instance list -c $C --all \
--query 'data.items[].{name:"display-name", state:"lifecycle-state", id:id}' --output table
CI=ocid1.computecontainerinstance.oc1..xxxx
oci container-instances container-instance get --container-instance-id $CI
Read lifecycle-state and lifecycle-details on the instance and on each container listed in containers. Then look at the containers on their own:
oci container-instances container list -c $C --container-instance-id $CI \
--query 'data.items[].{name:"display-name", state:"lifecycle-state", id:id}' --output table
oci container-instances container get --container-id ocid1.computecontainer.oc1..xxxx
When a container exits, the API records its exit code and exit time, and the restart policy decides what happens next. Field names vary by CLI version, so read the full get output instead of guessing a --query path.
For create failures, the work request often has the clearest message:
oci container-instances work-request list -c $C --output table
oci container-instances work-request list-errors --work-request-id ocid1.coreservicesworkrequest.oc1..xxxx
2. Image pull authorization
The service has to pull every image before any container starts. If it can't authenticate, or the image or tag doesn't exist, the instance fails.
First check the image path. An OCIR image URL looks like <region-key>.ocir.io/<tenancy-namespace>/<repo>:<tag>, for example fra.ocir.io/axabc123xyz/orders-api:1.4.2. Make sure the tag exists:
oci artifacts container image list -c $C --repository-name orders-api \
--query 'data.items[].{ver:version, created:"time-created"}' --output table
Private OCIR repos: use the resource principal, not a secret
Create a dynamic group for container instances in the compartment:
ALL {resource.type='computecontainerinstance', resource.compartment.id = 'ocid1.compartment.oc1..xxxx'}
Then let it read the repositories:
Allow dynamic-group ContainerInstanceDynamicGroup to read repos in compartment app-registry
You need both the dynamic group and the policy. With them in place, you don't need --image-pull-secrets for OCIR.
External registries (Docker Hub, GitHub, others): use a Vault secret
Store the registry credentials as a Vault secret whose content is JSON with username and password. Reference it at create time:
--image-pull-secrets '[{"secretType":"VAULT","registryEndpoint":"docker.io/myorg","secretId":"ocid1.vaultsecret.oc1..xxxx"}]'
The registryEndpoint must be a prefix of the imageUrl, or the secret isn't used. The dynamic group also needs to read the secret:
Allow dynamic-group ContainerInstanceDynamicGroup to read secret-bundles in compartment app-secrets
The service uses the latest secret version. If you rotate the registry password, update the secret before you launch new instances.
3. Can the subnet reach the registry?
Being allowed to pull isn't enough. The subnet in --vnics also needs a network path to the registry:
| Image source | Subnet needs |
|---|---|
| OCIR in the same region | Service gateway (All Services) in the route table, or NAT/internet gateway |
| Docker Hub, GitHub, Quay | NAT gateway (private subnet) or internet gateway (public subnet with a public IP) |
| File Storage volume | Mount target reachable from this subnet; NFS ports open in NSGs/security lists |
Check the subnet's route table:
SUBNET=$(oci container-instances container-instance get --container-instance-id $CI \
--query 'data.vnics[0]."subnet-id"' --raw-output)
RT=$(oci network subnet get --subnet-id $SUBNET --query 'data."route-table-id"' --raw-output)
oci network route-table get --rt-id $RT --query 'data."route-rules"' --output table
Also check egress: security lists and NSGs need an outbound rule for TCP 443 to the registry (or to the "All Services" CIDR label for the service gateway). For a deeper walk-through of the gateways, see the VCN routing post on this site.
4. Image too big for ephemeral storage
A container instance has 15 GB of ephemeral storage by default. The image has to download and unpack into it. Oracle's guidance is to keep the image under about half that (around 7.5 GB). If the image can't be unpacked, create fails.
Fixes:
- Use a smaller base image and multi-stage builds.
- Move large models or data out of the image into a File Storage or volume mount, or download them at startup.
5. The container starts, then exits
If the instance is ACTIVE but a container restarts in a loop, the image pulled fine and the problem is in the container. Get its logs:
CT=ocid1.computecontainer.oc1..xxxx
# Current run
oci container-instances container retrieve-logs --container-id $CT --file -
# The run that just crashed
oci container-instances container retrieve-logs --container-id $CT --is-previous true --file -
retrieve-logs returns only the most recent 256 KB. Use --is-previous to get the crash itself and not the next startup.
Common causes:
| Log shows | Cause | Fix |
|---|---|---|
exec format error | arm64 image on an x86 shape, or x86 image on CI.Standard.A1.Flex | Build a multi-arch image or match the shape |
executable file not found | command overrides the entrypoint with a wrong path | Fix command/arguments in --containers |
| Exits with code 137 | Out of memory | Raise memoryInGBs in --shape-config, or add a per-container memory limit |
| Exits with code 0 straight away | Short-lived job running under restart policy Always | Use restart policy Never or On failure for jobs |
| Can't reach DB, auth errors | Missing environment variable or secret | Check the container's environment settings |
The restart policy is set at create time with --container-restart-policy. The console offers Always (the default), Never and On failure. Get the API spelling for your CLI version with --generate-param-json-input. With Never or On failure, an instance whose containers have all stopped goes to INACTIVE. To run it again:
oci container-instances container-instance start --container-instance-id $CI --wait-for-state ACTIVE
Tip
To test a fix to the image or tag, push a new tag and recreate the instance. The CLI
updatecommands only change names and tags. Changes to the image or restart policy take effect only after the instance restarts, so recreating is the predictable way to do it.
6. Running, but the app can't be reached
Containers in one instance share the VNIC. Allow the app port on the subnet's security list or on an NSG attached to the instance:
oci network nsg rules add --nsg-id ocid1.networksecuritygroup.oc1..xxxx --security-rules '[
{"direction":"INGRESS","protocol":"6","source":"10.0.0.0/16","sourceType":"CIDR_BLOCK",
"tcpOptions":{"destinationPortRange":{"min":8080,"max":8080}}}]'
Then test from a host in the VCN with curl -v http://<private-ip>:8080/health. Make sure the app listens on 0.0.0.0 and not on 127.0.0.1.
Permissions for the people debugging
Operators need use compute-container-family (or use compute-containers) to retrieve logs. read alone isn't enough. Creating and deleting instances needs manage:
Allow group ContainerOps to manage compute-container-family in compartment apps
Allow group ContainerOps to use virtual-network-family in compartment network
Allow group ContainerOps to read repos in tenancy
Prevent it next time
- Create the dynamic group and the
read repospolicy once per compartment, as part of the landing zone, and not per deployment. - Use OCIR plus a service gateway for production images, so pulls don't depend on internet access or external rate limits.
- Pin image tags (or digests) in your deployment script, and check the tag exists before calling
create. - Keep images well under the ephemeral storage limit, and build for the shape's architecture.
- Choose the restart policy on purpose: Always for services, On failure or Never for jobs.
- Delete
FAILEDandINACTIVEinstances you no longer need. They still count toward service limits.