• Unable to create a container instance in OCI

    I was working with a customer to deploy a Docker image that I’d added to their OCI Container Registry, however when provisioning a Container Instance using this image it was failing with the following error πŸ›‘:

    A container image provided is not compatible with the processor architecture of the shape selected for the container instance.

    This is a pretty descriptive error message, that you will receive when attempting to deploy a container on a host machine that has a different CPU architecture than that of the image you are attempting to deploy, for example trying to deploy a container that uses an x64 based image to a host machine that has an ARM CPU.

    In this specific case, I was attempting to deploy a container to a AMD x64 machine – something which I had done numerous times successfully with this very image – a real case of “it works on my machine!“. After much head scratching I figured out what I’d done wrong πŸ’‘.

    I had used the Cloud Shell to create the image and deploy to the Container Registry (I ❀️ the Cloud Shell!).

    It turns out that it’s possible to select the arcihtecture to use for the Cloud Shell, I had been using x64 in my tenant, however the admin at the customer had ARM configured for their Cloud Shell therefore when it was building the Docker image it was pulling the ARM version of the base image therefore failing when attempting to deploy this to an AMD x64 host.

    There are two options to fix this:

    1. Provision the Container Instance on an Ampere (ARM) host
    2. Re-create the image using a Cloud Shell with the desired CPU architcture, in this case x64

    I was lazy and opted for option 1, to however to change the CPU architecture for Cloud Shell:

    • Launch Cloud Shell
    • Select Actions > Architecture
    • Choose the desired architecture (this is a per-user setting, not tenant-wide)

    Hope this helps somebody in the future!

  • Sending raw requests using the OCI CLI πŸ’»

    The OCI CLI includes a raw-request option, as the name suggests this is a useful way to send manual requests to OCI services instad of using the native CLI commands πŸ’».

    For example to list the buckets within a specific compartment I can run the following OCI CLI command πŸͺ£:

    oci os bucket list --compartment-id (OCID) --namespace-name (NameSpace)
    

    Or alternatively I could run the following using the OCI CLI raw-request command.

    oci raw-request --http-method GET --target-uri https://objectstorage.uk-london-1.oraclecloud.com/n/lrdkvqz1i7e6/b?compartmentId=ocid1.compartment.oc1..aaaaaaaa5yxo6ynmcebpvqgcapt3vpmk72kdnl33iomjt3bk2bcraqprp6fq
    

    This is a fairly simple read request against object storage, to help me understand how to formulate the URL (target-uri) I added –debug to the initial oci os bucket list CLI command that I ran. This provides a wealth of information on what happens “under the hood” when running a CLI command and helped me to understand the –target-uri I needed to use for the raw-request command.

    For more complex scenarios, such as creating resources or using a service e.g. analysing an image with AI Vision, you can add –generate-param-json-input to a CLI command and it will generate a JSON file which can be populated with the desired parameters that you can then pass to raw-request using the –request-body parameter.

    In terms of real-world usage, the only real use-case for this is with new services that you need to interact with, where there isn’t a CLI command available, with that being said this would mean that you couldn’t use the –debug parameter to help understand how to send the request using raw-request, so you’d need to rely on documentation and/or trial and error – probably the latter!

  • Introducing Optional Instructions for OCI Generative AI Agents πŸ”Ž

    Buried within the December 2024 release notes for the OCI Generative AI Agents service is this little gem πŸ’Ž:

    This now enables you to do some prompt engineering to influence the response produced by an agent, this is useful if you need to tailor the length, style and tone of the response from the agent. For example you may need the response to include a maximum of 3 bullet points.

    To provide additional instructions to an agent response, navigate to the agent and select Edit. Below you will see a field named Instructions for RAG generation, within this add the additional instructions. In the example below, I have simply asked it to crerate a short summary using a maximum of 3 bullet points.

    Here is a before/after comparison of the response from the agent, this is using an agent I built that is trained on UK immigration policy data.

    Before

    After

    There’s some other interesting features in the December release, including more detailed citations and the ability to override Object Storage citation links through custom Object Storage metadata.

  • Creating a front end for an OCI Generative AI Agent using Streamlit πŸŽ¨

    I stumbled upon an amazing tool recently called Streamlit. Streamlit makes it super-simple to create web apps using Python without any front-end dev experience (which was music to my ears!).

    I had one use-case which was perfect for Streamlit – creating a front end for OCI Generative AI Agents. I’ve built a number of PoCs recently and have used the OCI Console to demonstrate an OCI Generative AI Agent in action, whilst this is functional, it’s not particularly pretty πŸ˜€.

    If you want to know more about OCI Generative AI Agents, be sure to check out this short video that I created that walks through the end-to-end process of creating an agent in less than 10 minutes ⏱️.

    Anyway……back to the main topic. The advantage of using Streamlit is that it enables custom web apps to be created in minutes, which are highly customizable and therefore perfect for PoCs to demonstrate the art of the possible .

    Before I jump into sharing the code, this is how the end result looked (running locally on my Mac, will also work on Windows too) – using an agent that I developed to help understand UK immigration policy πŸ“„. Here I am asking about the rules for an entrepreneur.

    Installing Streamlit is a breeze using the single command below.

    pip install streamlit
    

    Once I’d done this, I put together the following Python script to create the web app, this can also be downloaded from GitHub.

    Disclaimer: I’m no developer and this code is a little hacky, but it gets the job done!

    The following variables need to be updated before running the script – further info can be found in the code comments:

    • st.title – Set’s the title of the page
    • st.sidebar.image – Configures the image to use in the sidebar
    • config – Set’s the OCI SDK profile to use, further info on this can be found here – https://docs.oracle.com/en-us/iaas/Content/API/Concepts/sdkconfig.htm
    • service_ep – Defines the Generative AI Agent service endpoint to connect to (this varies by region)
    • agent_ep_id – Sets the OCID of the agent to connect to
    import streamlit as st
    import time
    import oci
    
    # Page Title
    st.title("OCI Generative AI Agents Demo 🧠") # Update this with your own title
    
    # Sidebar Image
    st.sidebar.image("https://brendg.co.uk/wp-content/uploads/2021/05/myavatar.png") # Update this with your own image
    
    # OCI GenAI settings
    config = oci.config.from_file(profile_name="DEFAULT") # Update this with your own profile name
    service_ep = "https://agent-runtime.generativeai.us-chicago-1.oci.oraclecloud.com" # Update this with the appropriate endpoint for your region, a list of valid endpoints can be found here - https://docs.oracle.com/en-us/iaas/api/#/en/generative-ai-agents-client/20240531/
    agent_ep_id = "ocid1.genaiagentendpoint.oc1.us-chicago-1.amaaaaaaayvpzvaa7z2imflumr7bbxeguh6y7bpnw2yie4lca2usxrct" # Update this with your own agent endpoint OCID, this can be found within Generative AI Agents > Agents > (Your Agent) > Endpoints > (Your Endpoint) > OCID
    
    # Response Generator
    def response_generator(textinput):
        # Initialize service client with default config file
        generative_ai_agent_runtime_client = oci.generative_ai_agent_runtime.GenerativeAiAgentRuntimeClient(config,service_endpoint=service_ep)
    
        # Create Session
        create_session_response = generative_ai_agent_runtime_client.create_session(
            create_session_details=oci.generative_ai_agent_runtime.models.CreateSessionDetails(
                display_name="USER_Session",
                description="User Session"),
            agent_endpoint_id=agent_ep_id)
    
        sess_id = create_session_response.data.id
    
        response = generative_ai_agent_runtime_client.chat(
            agent_endpoint_id=agent_ep_id,
            chat_details=oci.generative_ai_agent_runtime.models.ChatDetails(
                user_message=textinput,
                session_id=sess_id))
    
        #print(str(response.data))
        response = response.data.message.content.text
        return response
    
    # Initialize chat history
    if "messages" not in st.session_state:
        st.session_state.messages = []
    
    # Display chat messages from history on app rerun
    for message in st.session_state.messages:
        with st.chat_message(message["role"]):
            st.markdown(message["content"])
    
    # Accept user input
    if prompt := st.chat_input("How can I help?"):
        # Add user message to chat history
        st.session_state.messages.append({"role": "user", "content": prompt})
        # Display user message in chat message container
        with st.chat_message("user"):
            st.markdown(prompt)
    
        # Display assistant response in chat message container
        with st.chat_message("assistant"):
            response = response_generator(prompt)
            write_response = st.write(response)
        # Add assistant response to chat history
        st.session_state.messages.append({"role": "assistant", "content": response})
    

    Once this file has been saved, it’s simple to run with a single command:

    streamlit run OCI-GenAI-Agents-Streamlit.py
    

    It will then automatically launch a browser and show the web app in action πŸ–₯️

    This basic example can easily be updated to meet your requirements, the Streamlit documentation is very comprehensive and easy to follow with some useful examples – https://docs.streamlit.io/.

  • Unauthorized to use OML application error when trying to obtain an OML token from an Oracle Autonomous database with a private endpoint βŒ

    Probably the longest title I’ve ever had for a post!

    I have an Oracle Autonomous Database that I created a private endpoint for and published via a public load balancer in OCI……my reason for this complexity – I wanted to use a custom vanity URL to access the database and this is the supported way to do this. If want to know more about setting this up, be sure to check out this step by step guide πŸ“–.

    Once I’d got this setup, everything worked as expected apart from one small issue – when trying to get a token via REST so that I could call an Oracle Machine Learning model within the database I received the following error ❌.

    b'{“error_message”:”\’DEMO1USER\’ unauthorized to \’use OML application\’”,”errorCode”:0,”request_id”:”OMLIDMREST-955f999622584d33a70″}’

    I was calling the REST API via Python, but other methods such as Curl returned the same error (further details on calling the REST API to get a token and authenticate can be found here). The user had the relevant permissions so it was definitely something else πŸ€”.

    The trick to fixing this is to update the URL that is called to obtain the token, rather than using this:

    https://oml-cloud-service-location-url/omlusers/api/oauth2/v1/token

    The URL needs to be updated to include the OCID of the OCI tenancy and the name of the database to connect to, like this:

    https://oml-cloud-service-location-url/omlusers/tenants/TenancyOCID/databases/DatabaseName/api/oauth2/v1/token

    For example, I was originally using this URL:

    https://adb.brendg.co.uk/omlusers/api/oauth2/v1/token

    I had to update this to:

    https://adb.brendg.co.uk/omlusers/tenants/ocid1.tenancy.oc1..aaaaaabbjdjwnd3krfpjw23erghw4dxnvadd9w6j2hwcirea22qrtfam24mq/databases/DemoDB/api/oauth2/v1/token

    The reason for this, is that when using a custom (vanity) URL to access the REST endpoint, it doesn’t know which tenancy and database you are trying to obtain an authentication token for, therefore you need to specify this in the REST endpoint.

    Once I’d done this, it worked like magic πŸͺ„

  • OCI AI Vision – UK Oracle User Group Conference 2024 πŸ‡¬πŸ‡§

    I recently had the privilege of presenting a session on OCI AI Vision at the UK Oracle User Group conference in Birmingham πŸ™οΈ.

    img_2246-1

    The slides I presented can be downloaded from here and include a video of the second demo in my session (the important one).

    It was an absolutely fantastic event, with some brilliant sessions – I learnt a lot! 🧠

  • How to create a free SSL certificate with Let’s Encrypt…and as a bonus use this certificate with Oracle Analytics Cloud πŸ”

    I needed an SSL certificate recently as wanted to make an instance of Oracle Analytics Cloud available publicly with a nice vanity URL, rather than https://demo1analyticscloud-lrmvtbrwx-ld.analytics.ocp.oraclecloud.com, something a little more memorable, such as https://oac.oci-demo.co.uk.

    To do this I needed an SSL certificate and decided to use Let’s Encrypt as they provide free SSL certificates (with a validity period of 90 days).

    It was relatively straightforward to create a certificate using the Certbot client for macOS, to do this I did the following:

    Step 1 – Installed Certbot using the following command

    brew install certbot
    

    Step 2 – Created a directory to store the generated certificates

    mkdir certs
    cd certs
    

    Step 3 – Create the certificate request using Certbot

    This uses the DNS challenge type, which is ideal when you need to create a certificate for use on a system that doesn’t provide native integration with Certbot (such as Oracle Analytics Cloud). Replace “e-mail address” with a valid address to use for renewal reminders.

    cd certs
    certbot certonly --manual --preferred-challenges=dns --config-dir config --work-dir workdir --logs-dir logs --agree-tos -m e-mail address --key-type rsa
    

    When this command has been run, it will ask for the hostname to create the SSL certificate for. In my case I requested a certificate for demo1oac.oci-demo.co.uk.

    After hitting enter, it then provides a DNS record that needs to be created to validate domain ownership.

    I host my DNS within OCI, so this was as simple as creating a DNS TXT record using the OCI Console (the process will vary depending on your DNS provider).

    I then used the link within the instructions to validate the presence of the DNS TXT records that I had just created.

    Once I’d verified that the DNS record was available publicly, I hit enter and the SSL certificates were created for me!

    Step 4 – Configure OAC to use a custom hostname with SSL (example)

    I then navigated to Oracle Analytics Cloud within the OCI Console and within Vanity URL selected Create.

    I entered the hostname for the vanity URL – demo1oac.oci-demo.co.uk. I then uploaded the certificates that had just been generated.

    The mapping between certificate types and the .pem files created is as follows:

    • Certificate = cert1.pem
    • Private Key = privkey1.pem
    • Certificate Authority chain file = chain1.pem

    I then hit Create to apply the configuration. A final step was for me to create a DNS entry to point demo1oac.oci-demo.co.uk to the public IP address of the OAC instance.

    I then waited a few minutes for the DNS record to come to life and then browsed to https://demo1oac.oci-demo.co.uk and it worked!

  • Unable to connect to a Kubernetes cluster in OCI using kubectl πŸ”Œ

    The time finally came for me to get hands on with Kubernetes on OCI (or OKE as it’s affectionately know).

    Spinning up a Kubernetes cluster was an absolute breeze, however when I started to work through the Quick Start….or not so Quick Start for me – I stumbled up an error when attempting to deploy the sample app to my cluster.

    When I ran the command in Step 3 I received the following error:

    error: error validating “https://k8s.io/examples/application/deployment.yaml”: error validating data: failed to download openapi: the server has asked for the client to provide credentials; if you choose to ignore these errors, turn validation off with –validate=false

    Looked like some form of authentication issue, after much head scratching and experimentation I figured out what the problem was (it took me far too long ⏱️).

    I have multiple profiles specified within my OCI CLI configuration file, example below (with the juicy bits removed!):

    The OKE cluster I needed to connect to is within the tenancy I have named PubSec, if I take a look at the Kubernetes config file (located in “.kube” within my user profile), I could see that this uses the OCI CLI to connect to the cluster – however as it doesn’t specify a profile within the OCI CLI config this will use the DEFAULT profile, in my specific case I needed to override this to uses the PubSec profile.

    I resolved this by adding the highlighted lines (below) to the Kubernetes config file within “.kube”. This tells the OCI CLI to connect to the cluster using the PubSec profile rather than DEFAULT.

    Once I’d updated this, saved and re-sarted the terminal, I ran the command again and it worked like magic πŸͺ„

  • Creating a Generative AI Agent in less than 10 minutes.

    There’s been a lot of buzz about Generative AI Agents recently, so I thought that I’d take Oracle Gen AI Agents for a spin 🧠.

    In this short video (<10 minutes ⏱️), I walk through the full end-to-end process of creating a Gen AI agent within OCI that uses the power of a LLM and business data to provide contextually relevant answers to business questions, saving users time and reducing costs πŸ‘©β€πŸ’».

  • Creating sample data in Oracle Autonomous Database using AI πŸ§ 

    I’ve recently posted a short video on YouTube that walks through the process of creating and loading sample data into Oracle Autonomous Database using AI – this feature is fully baked into the product too!

    This will be a huge timesaver for me as I create a lot of demo’s πŸ‘¨β€πŸ’».