Resolving Oracle Cloud “Out of Capacity” issue and getting free VPS with 4 ARM cores / 24GB of memory (using OCI CLI)
Update 2024: This approach is still functional, but many Reddit users now recommend upgrading to Pay As You Go (PAYG) for the best experience. With PAYG, you’ll continue to enjoy all the free benefits without any additional cost, but you’ll also receive priority for launching instances and are less likely to face “Out of host capacity” errors. Additionally, PAYG unlocks more types of OCI resources, including free Kubernetes-related infrastructure if that’s something you’re interested in. It’s important to set up budget alerts as a safety net and be mindful of the resources you deploy and their associated costs. This way, you can take full advantage of PAYG while keeping your spending in check.
Very neat and useful configuration was recently announced at Oracle Cloud Infrastructure (OCI) blog as a part of Always Free tier. Sometimes it’s complicated to launch an instance due to the “Out of Capacity” error. Here we’re solving that issue as Oracle constantly adds capacity from time to time.
Each tenancy gets the first 3,000 OCPU hours and 18,000 GB hours per month for free to create Ampere A1 Compute instances using the VM.Standard.A1.Flex shape (equivalent to 4 OCPUs and 24 GB of memory).
Starting from Oracle Cloud Infrastructure (OCI) CLI installation. If you prefer PHP, please look here in my similar tutorial https://hitrov.medium.com/resolving-oracle-cloud-out-of-capacity-issue-and-getting-free-vps-with-4-arm-cores-24gb-of-6ecd5ede6fcc.
Generating API key
After logging in to OCI Console, click profile icon and then “User Settings”
Go to Resources -> API keys, click “Add API Key” button
Make sure “Generate API Key Pair” radio button is selected, click “Download Private Key” and then “Add”.
Copy the contents from textarea and save it to file with a name “config”. I put it together with *.pem file in newly created directory /home/ubuntu/.oci
That’s all about the API key generation part.
Setting up CLI
Specify config location
OCI_CLI_RC_FILE=/home/ubuntu/.oci/config
If you haven’t added OCI CLI binary to your PATH, run
alias oci='/home/ubuntu/bin/oci'
(or whatever path it was installed).
Set permissions for the private key
oci setup repair-file-permissions --file /home/ubuntu/.oci/oracleidentitycloudservice***.pem
Test the authentication (user value should be taken from textarea when generating API key):
oci iam user get --user-id ocid1.user.oc1..aaaaaaaax72***d3q
Output should be similar to
Acquiring launch instance params
We need to know which Availability Domain is always free. Click Oracle Cloud menu -> Compute -> Instances
Click “Create Instance” and notice which one has “Always Free Eligible” label in Placement Section. In our case it’s AD-2.
Almost every command needs compartment-id param to be set. Let’s temporary save it to env var (replace with your “tenancy” value from the config file):
export C=ocid1.tenancy.oc1..aaaaaaaakpx***mpa
Now let’s collect all needed values for launch instance command
- availability-domain
- shape
- subnet-id
- image-id
oci iam availability-domain list --all --compartment-id=$C
Output will be similar to
{
"data": [
...
{
"compartment-id": "ocid1.tenancy.oc1..aaaaaaaakpx***mpa",
"id": "ocid1.availabilitydomain.oc1..aaaaaaaalcd***m2q",
"name": "FeVO:EU-FRANKFURT-1-AD-2"
},
...
]
}
Remember, we need to pickup it’s name — the one which is free of charge(AD-2). Setting temporary env var with it’s value:
export A=FeVO:EU-FRANKFURT-1-AD-2
Then let’s review shapes:
oci compute shape list --compartment-id=$C
Here we are interested in this one — VM.Standard.A1.Flex:
{
"data": [
...
{
"baseline-ocpu-utilizations": null,
"gpu-description": null,
"gpus": 0,
"is-live-migration-supported": false,
"local-disk-description": null,
"local-disks": 0,
"local-disks-total-size-in-gbs": null,
"max-vnic-attachment-options": {
"default-per-ocpu": 1.0,
"max": 24.0,
"min": 2
},
"max-vnic-attachments": 2,
"memory-in-gbs": 6.0,
"memory-options": {
"default-per-ocpu-in-g-bs": 6.0,
"max-in-g-bs": 512.0,
"max-per-ocpu-in-gbs": 64.0,
"min-in-g-bs": 1.0,
"min-per-ocpu-in-gbs": 1.0
},
"min-total-baseline-ocpus-required": null,
"networking-bandwidth-in-gbps": 1.0,
"networking-bandwidth-options": {
"default-per-ocpu-in-gbps": 1.0,
"max-in-gbps": 40.0,
"min-in-gbps": 1.0
},
"ocpu-options": {
"max": 80.0,
"min": 1.0
},
"ocpus": 1.0,
"processor-description": "3.0 GHz Ampere\u00ae Altra\u2122",
"shape": "VM.Standard.A1.Flex"
},
...
]
}
I hope that you previously created at least VM.Standard.E2.1.Micro (AMD processor based) from the console— two of them are “Always Free”. If not, please do that — we need VNC, subnet, route table, security list etc. to exist.
oci network subnet list --compartment-id=$C
Please notice the id:
{
"data": [
{
"availability-domain": null,
"cidr-block": "10.0.0.0/24",
"compartment-id": "ocid1.tenancy.oc1..aaaaaaaakpx***mpa",
"defined-tags": {
"Oracle-Tags": {
"CreatedBy": "***",
"CreatedOn": "2021-01-26T13:51:31.332Z"
}
},
"dhcp-options-id": "ocid1.dhcpoptions.oc1.eu-frankfurt-1.aaaaaaaafh4***cvq",
"display-name": "subnet-20210126-1549",
"dns-label": "subnet01261551",
"freeform-tags": {},
"id": "ocid1.subnet.oc1.eu-frankfurt-1.aaaaaaaaahbb***faq",
"ipv6-cidr-block": null,
"ipv6-virtual-router-ip": null,
"lifecycle-state": "AVAILABLE",
"prohibit-internet-ingress": false,
"prohibit-public-ip-on-vnic": false,
"route-table-id": "ocid1.routetable.oc1.eu-frankfurt-1.aaaaaaaaqwe***p76q",
"security-list-ids": [
"ocid1.securitylist.oc1.eu-frankfurt-1.aaaaaaaaagnn***tca"
],
"subnet-domain-name": "subnet***.vcn***.oraclevcn.com",
"time-created": "2021-01-26T13:51:31.534000+00:00",
"vcn-id": "ocid1.vcn.oc1.eu-frankfurt-1.amaaaaaalox***y4a",
"virtual-router-ip": "10.0.0.1",
"virtual-router-mac": "00:00:17:***"
}
]
}
And save it to the variable
export S=ocid1.subnet.oc1.eu-frankfurt-1.aaaaaaaaahbb***faq
Listing images.
oci compute image list --compartment-id=$C --shape=VM.Standard.A1.Flex
I prefer to have all the software needed for development out of the box — my choice is latest “Oracle Linux Cloud Developer”.
{
"data": [
...
{
"agent-features": null,
"base-image-id": null,
"billable-size-in-gbs": 14,
"compartment-id": null,
"create-image-allowed": true,
"defined-tags": {},
"display-name": "Oracle-Linux-Cloud-Developer-8.4-aarch64-2021.06.18-0",
"freeform-tags": {},
"id": "ocid1.image.oc1.eu-frankfurt-1.aaaaaaaa23zlxgcvdgb2zn4ffik6rda4g5daa5wa42svsgp4enljv4ywv6wa",
"launch-mode": "NATIVE",
"launch-options": {
"boot-volume-type": "PARAVIRTUALIZED",
"firmware": "UEFI_64",
"is-consistent-volume-naming-enabled": true,
"is-pv-encryption-in-transit-enabled": true,
"network-type": "PARAVIRTUALIZED",
"remote-data-volume-type": "PARAVIRTUALIZED"
},
"lifecycle-state": "AVAILABLE",
"listing-type": null,
"operating-system": "Oracle Linux Cloud Developer",
"operating-system-version": "8",
"size-in-mbs": 51200,
"time-created": "2021-06-24T20:36:22.659000+00:00"
},
...
]
}
Saving it’s image ID:
export I=ocid1.image.oc1.eu-frankfurt-1.aaaaaaaa23zlxgcvdgb2zn4ffik6rda4g5daa5wa42svsgp4enljv4ywv6wa
We also need to have a few small .json files:
- instanceOptions.json
{
"areLegacyImdsEndpointsDisabled": false
}
- shapeConfig.json (adjust the OCPUs count and RAM if needed). Possible values are 1/6, 2/12, 3/18 and 2/24, respectively. Please notice that “Oracle Linux Cloud Developer” image can be created with at least 8GB of RAM (so it should have minimum 1/8).
{
"ocpus": 4,
"memoryInGBs": 24
}
- availabilityConfig.json
{
"recoveryAction": "RESTORE_INSTANCE"
}
In order to have secure shell (SSH) access to the instance you need to have a keypair, e.g. ~/.ssh/id_rsa and ~/.ssh/id_rsa.pub. Second one (public key) filename should be provided to a command below. The are plenty of tutorials on how to do that, we won’t cover this part here.
Finally
oci compute instance launch \
--availability-domain $A \
--compartment-id $C \
--shape VM.Standard.A1.Flex \
--subnet-id $S \
--assign-private-dns-record true \
--assign-public-ip false \
--availability-config file:///home/ubuntu/availabilityConfig.json \
--display-name my-new-instance \
--image-id $I \
--instance-options file:///home/ubuntu/instanceOptions.json \
--shape-config file:///home/ubuntu/shapeConfig.json \
--ssh-authorized-keys-file /home/ubuntu/.ssh/id_rsa.pub
You can now setup crontab to run this command e.g. every 5 minutes. Create .sh script file (“exporting” needed params values before the actual command call) and make sure cron user is able to access private key. We won’t cover this part.
Output (I tested with VM.Standard.E2.1.Micro shape to not remove my existing ARM instances):
I believe it’s pretty safe to leave the cron running and check cloud console once per few days. Because when you’ll succeed, usually you won’t be able to create more instances than allowed — but start getting something like
{
"code": "LimitExceeded",
"message": "The following service limits were exceeded: standard-a1-memory-count, standard-a1-core-count. Request a service limit increase from the service limits page in the console. "
}
or (again)
{
"code": "InternalError",
"message": "Out of host capacity."
}
At least that’s how it worked for me.
If you switched to “Pay as you go” plan, you must consider how to stop OCI CLI API calls after you succeed–to not run into unintended charges. For example, you can setup a command
oci compute instance list --compartment-id $C
…somehow check it’s output periodically to know when cron needs to be disabled. That’s not related to our issue here.
If you want safety way with such check there is one which I introduced with PHP here https://hitrov.medium.com/resolving-oracle-cloud-out-of-capacity-issue-and-getting-free-vps-with-4-arm-cores-24gb-of-6ecd5ede6fcc
Assigning public IP address
We are not doing this during the command run due to the default limitation (2 ephemeral addresses per compartment). That’s how you can achieve this. When you’ll succeed with creating an instance, open OCI Console, go to Instance Details -> Resources -> Attached VNICs by selecting it’s name
Then Resources -> IPv4 Addresses -> … -> Edit
Choose ephemeral and click “Update”
Conclusion
That’s how you will login when instance will be created (notice opc default username)
ssh -i ~/.ssh/id_rsa opc@ip.add.re.ss
If you didn’t assign public IP, you can still copy internal FQDN or private IP (10.x.x.x) from the instance details page and connect from your other instance in the same VNIC. e.g.
ssh -i ~/.ssh/id_rsa opc@instance-20210714-xxxx.subnet.vcn.oraclevcn.com
Thanks for reading!