Wednesday, 13 May 2026

Oracle Database 19.31 Patch Hold: What DBAs on Exadata 25.2 Need to Know

If you’ve been trying to download the latest Oracle Database 19.31 Release Update (RU) lately and found the download pages curiously empty, you aren't alone. Oracle has officially placed a temporary hold on this specific RU for Exadata environments.

The move comes after several customers reported intermittent internal errors specifically when running 19.31 on Exadata System Software 25.2. Here is a breakdown of what happened, why it matters, and how to keep your systems stable.

What’s the Problem?
Oracle recently published a My Oracle Support (MOS) advisory regarding a conflict between the 19.31 DBRU and the newer Exadata 25.2 software stack. It appears that a specific optimization path related to temporary tablespace processing is triggering internal failures during SQL execution.

Because the issue is severe enough to cause application instability, Oracle took the proactive step of removing the 19.31 patch binaries while they work on a corrected revision.
Key Symptoms to Watch For:
If you are already on this combination, you might see a spike in:
  • ORA-00600 internal errors (specifically signatures like QERHNITERATEOVERBUFFERS.1 or kcblsltio_1)
  • Unexpected SQL statement failures and session terminations
  • Background process crashes that disrupt application uptime

Issues specifically during heavy ETL, analytics, or workloads that lean hard on temporary segments.

Workaround: Disabling the Optimization
If you have already deployed 19.31 to your Exadata 25.2 environment, you don't necessarily need to roll back immediately. Oracle has provided a "hidden parameter" workaround that disables the problematic optimization path.

To mitigate the risk immediately, run the following:
-- For the current instance
alter system set "_kcfis_fctempopt_mode" = 0;

-- For RAC environments (persistent across nodes)
alter system set "_kcfis_fctempopt_mode" = 0 scope=both sid='*';

Note: As with any hidden parameter, make sure to document this in your operational runbook and monitor performance. Once Oracle releases the corrected RU, you will likely need to unset this parameter.

Who is Affected?
The good news is that this is a relatively narrow issue. It currently only impacts:
Database Version: 19.31
Infrastructure: Exadata System Software 25.2.*
If you are running 19.31 on standard Linux/Unix servers, or if your Exadata units are on older software versions, you are likely in the clear.

reference: We released a MOS Note with detailed information: (KB888427) Oracle Database 19.31 Patch Hold Due to ORA-00600 Errors on Exadata 25.2: 

Thursday, 7 May 2026

Copy Fail: The New "Dirty Pipe" Haunting the Linux Kernel (CVE-2026-31431)

1. What is Copy Fail (CVE-2026-31431)?
Copy Fail is a logic flaw in the Linux kernel's crypto-subsystem (specifically the algif_aead module). It allows an unprivileged user to gain full root access in seconds.  

Root Cause: A performance optimization introduced in 2017 allowed the kernel to perform in-place cryptographic operations (reusing the same memory for input and output).  

Flaw: By using the splice() system call, an attacker can trick the kernel into using the Page Cache (the kernel’s in-memory copy of files) as a writable buffer.

Result: An attacker can perform a controlled 4-byte write into any readable file in memory. They typically target a binary like /usr/bin/su to change its logic on the fly and grant themselves root privileges without ever touching the actual file on the disk.
 
2. Why it’s Critical for Cloud & Kubernetes
This is particularly dangerous for multi-tenant environments:
Container Breakout: Because the Page Cache is shared across the entire host kernel, a user in one container can corrupt a file that affects the host and all other containers on that node.  

Reliability: Unlike many exploits that rely on race conditions (timing luck), Copy Fail is deterministic. It works every time, regardless of system speed or load.  

Small Footprint: The exploit can be triggered by a script as small as 732 bytes.
        
3.High-Level Comparison: 
Copy Fail vs. Dirty Pipe If your stakeholders remember Dirty Pipe (2022), this is its modern sibling.  
Feature                   Dirty Pipe (CVE-2022-0847)      Copy Fail (CVE-2026-31431)
SubsystemPipe      Buffer / Splice                                Crypto API / Splice
Trigger                    Uninitialized pipe flags                AEAD in-place logic flaw
Scope                       Linux Kernels 5.8+                       Every major distro since 2017
Detection               Moderate (File modifications)    Difficult (Direct Memory corruption)


    

Sunday, 26 April 2026

Oracle 26 AI New DB Parameter CALENDAR_FISCAL_YEAR_START

Business doesn’t follow the January to December calendar, but the database does. Every time you build a report, a dashboard, or even a simple query, you end up rewriting the same fiscal logic again and again.
Some teams maintain calendar tables. Others push the logic into BI tools. In many cases, it ends up duplicated across ETL pipelines, reports, and applications. And sooner or later, something goes out of sync.

Oracle 26ai introduces a small but very practical fix for this: CALENDAR_FISCAL_YEAR_START.
Checking the Parameter
show parameter CALENDAR_FISCAL_YEAR_START
NAME                       TYPE   VALUE 
-------------------------- ------ ----- 
calendar_fiscal_year_start string       

At this point it’s unset, which means Oracle is still operating on the standard calendar year.

Set the start of the fiscal year to June 1:
ALTER SESSION SET CALENDAR_FISCAL_YEAR_START = '01-JUN-2026', 'DD-MON-YYYY';

Only the month and day really matter, so this works as well:
ALTER SESSION SET CALENDAR_FISCAL_YEAR_START = '01-JUN', 'DD-MON';

Now let’s see how Oracle interprets dates once this is set.
Check June 15, 2026:
SELECT FISCAL_QUARTER('15-JUN-2026');
FISCAL_QUARTER
-------------
Q1-FY2027

And May 15, 2026:
SELECT FISCAL_QUARTER('15-MAY-2026');
FISCAL_QUARTER
-------------
Q4-FY2026

This is exactly how most organizations expect fiscal periods to behave when the year starts in June.

Why This Actually Matters:
This parameter removes a lot of quiet complexity that has been sitting in systems for years.
First, it cleans up SQL. You don’t need CASE statements or custom logic just to determine fiscal quarters. The database understands it natively.
Second, it brings consistency. Instead of every layer calculating fiscal periods differently, the logic lives in one place. That alone eliminates a lot of subtle reporting issues.
Third, it simplifies data pipelines. There’s no need to maintain fiscal calendar tables or transformation logic in ETL jobs. Less code, fewer moving parts, fewer things to break.


Saturday, 18 April 2026

What is Ollama Serve (REST API)

Running LLMs locally is becoming very common, and tools like Ollama make it extremely simple.
But one feature that really unlocks its power is
ollama serve
This turns your local machine into a REST API server for AI models.

When we run:
ollama serve

It starts a local web server. This server allows other applications to talk to your AI models using HTTP requests.

Without serve → You manually run prompts in terminal
With serve → Your apps can call the model like an API

Default API Endpoint: Once the server starts
http://localhost:11434  becomes base URL.

Example API Call
Here’s a  request:
curl http://localhost:11434/api/generate -d '{
  "model": "llama3",
  "prompt": "Explain cloud computing"
}'

Sample API Output (With Metrics):
{
  "model": "llama3",
  "created_at": "2026-04-18T12:10:00Z",
  "response": "Cloud computing is the delivery of computing services over the internet...",
  "done": true,

  "total_duration": 2450000000,
  "load_duration": 800000000,
  "prompt_eval_count": 12,
  "prompt_eval_duration": 200000000,
  "eval_count": 65,
  "eval_duration": 1450000000
}


Now let’s understand this response
Basic Response Fields
model  ===> llama3
created_at  ===>  2026-04-18T12:10:00Z
response    ===>  "Cloud computing is the delivery of computing services over the internet..."
done    ===>  true , Means response is complete, No more data coming

Performance Metrics:
1. total_duration ===>   2450000000 ns → ~2.45 seconds
This is the total time taken ==> From Request received To Final response sent

2. load_duration  ===> 800000000 ns → ~0.8 seconds
Time taken to load the model into memory 
This usually happens On first request ,When model is not already loaded

3. prompt_eval_count  ===>  12 tokens
Number of tokens in your input  

4. prompt_eval_duration   ===>  200000000 ns → ~0.2 seconds

Time model spent reading your question

5. eval_count    ===>  65 tokens

Number of tokens generated in response , This directly affects response size,Cost (in cloud scenarios) and Latency

6. eval_duration    ===>  1450000000 ns → ~1.45 seconds

Time spent generating the response , This is Actual thinking + answering time

Friday, 17 April 2026

Understanding LLM Models: Basics That Help You Choose the Right One

LLMs are everywhere now. Every tool, every platform, every new feature seems to be powered by them.

But when it comes to actually choosing a model, things quickly get confusing.
You start seeing terms like parameters, quantization, context length… and it all feels a bit heavy

This blog will help you understand the key basics in a simple way.

Model Architecture – How the Model Thinks

At a high level, architecture is just how the model is designed to process information.  
Most modern LLMs use something called a Transformer. You don’t need to go deep into it — just know this:
It helps the model understand relationships between words.
Instead of reading text word-by-word like old systems, it looks at the whole sentence and figures out what matters more.
That’s how it understands meaning, tone, and context.

Why should you care?
Because better architecture usually means:
More accurate responses
Better understanding of complex inputs
Smarter outputs overall

Parameters – How Big the Model Is
This is the one you’ll hear the most.

Parameters are basically the size of the model.
More parameters = more “learned knowledge”.

Think of it like this:
Small models are quick and efficient
Large models are more knowledgeable but heavier

But bigger isn’t always better.

Yes, large models can reason better and handle complex tasks.
But they also:
Cost more
Need more compute
Can be slower

So the real question is not “What’s the biggest model?”
It’s “What’s enough for my use case?”

Quantization – Making Models Practical
Quantization is simply a way to make models smaller and faster. Without it, most large language models would be too heavy to run outside of high-end infrastructure.

What “Quantization” Really Means
LLMs normally store weights in high precision like:
FP32 (32-bit float)
FP16 (16-bit float)

Quantization reduces that to:
8-bit (Q8)
6-bit (Q6)
5-bit (Q5)
4-bit (Q4)

So instead of each weight taking 16–32 bits, it might take just 4 bits.
Result:
Much smaller model size
Faster inference
Can run on CPU or smaller GPUs

But:
Slight loss in quality (depends on method)

And honestly, in many real-world cases, that quality drop is barely noticeable. Especially for things like chat, summaries, or general-purpose usage.

You’re basically making a smart trade:
a tiny bit of precision for a huge gain in usability

Where It Gets Slightly Confusing (But Important)
Once you start using quantized models, you’ll see names like:
Q4_0
Q4_1
Q4_K_M
Q4_K_S

At first, it looks like random naming. But there’s actually a simple idea behind it.
Q4 → means 4-bit quantization
The part after _ → tells you how the compression is done
Not All Q4 Are Equal

Older versions like:
Q4_0 → more aggressive, lower quality
Q4_1 → slightly better

Smarter Quantization (The K Family)
Q4_K_M
Q4_K_S

use better techniques (you’ll often see them in tools like llama.cpp).

Instead of compressing everything the same way, they:
Work in small blocks
Apply smarter scaling
Keep important information more intact

Same 4-bit size, but noticeably better quality.
Picking the Right One (Simple Rule)
Q4_K_M → best balance (default choice)
Q4_K_S → slightly faster, slightly less accurate

If you don’t want to overthink it, just go with Q4_K_M.

 
Context Length – How Much It Can Keep in Mind

Context length is like the model’s short-term memory.

It decides how much text the model can look at in one go.
Short context:
Faster
Cheaper
But forgets earlier parts quickly

Long context:
Can handle long documents
Better for conversations and analysis
Slightly more expensive

If your work involves long PDFs, logs, or conversations — this matters a lot.

Embedding Length – How Well It Understands Meaning
This one is less talked about, but very important.

Before a model understands text, it converts words into numbers. These are called embeddings.

Embedding length is just how detailed that representation is.
Higher dimension → richer understanding of meaning

This becomes critical when you're building things like:
Search systems
Recommendations
RAG (retrieval-based AI apps)

If your use case involves “finding similar things” — embeddings matter more than you think.

So, How Do You Choose?

Instead of chasing the biggest or newest model, think in terms of your actual need.

If you need deep reasoning → go for larger models
If you need speed and cost efficiency → smaller + quantized models
If you deal with long inputs → prioritize context length
If you're building search or RAG → focus on embedding quality

It’s always a trade-off. There’s no perfect model.

Sunday, 22 March 2026

OCFS2 setup for shareable ( Read/write) Block Volume for Multiple Cluster Compute instances

This blog explains how to create shareable block volumes and mount them across multiple OCI compute nodes. 

Step 1: Create the block volume in OCI
In the OCI console , create a block volume in the same availability domain as your compute instances. Pick size and performance to match your workload.

Step 2: Attach the volume to each cluster node

  1. Open the volume (or the instance) and choose Attach block volume
  2. Set Attachment type to iSCSI (not paravirtualized for this flow).
  3. Set Attachment access to Read/write – shareable.

Attach the same volume to all nodes in cluster, with the same settings each time.

Step 3: Run the iSCSI commands on each node
After each attachment, OCI shows iSCSI IPv4 commands & information for that attachment.
Open it and copy the full set of `iscsiadm` commands  (discover, login, and any optional rescan steps OCI lists).

1. SSH to the node
2. Paste and run those commands as root or with `sudo`, exactly as OCI documents for your image (Oracle Linux / RHEL-style hosts usually use the `iscsiadm` sequence from the console).
Repeat on every node so each host has an active iSCSI session to the same volume.

Check: On each node run `lsblk` (or `fdisk -l`). You should see a new disk (often `/dev/sdb` or similar).

OCFS2 needs a small cluster layout file. The file must list all nodes in the cluster. `node_count` must match how many `node:` blocks you define.
Step 4: Create the config directory
On each node:
sudo mkdir -p /etc/ocfs2

Step 5: Edit `cluster.conf`
sudo vi /etc/ocfs2/cluster.conf
cluster:
    node_count = 2
    name = ocfs2

node:
    number = 0
    cluster = ocfs2
    ip_port = 7777
    ip_address = 10.0.0.94
    name = jay-db-node01

node:
    number = 1
    cluster = ocfs2
    ip_port = 7777
    ip_address = 10.0.0.95
    name = jay-db-node02


Use one cluster name (here `ocfs2`)
Private IPs your nodes use to talk to each other (often the VCN private address).
`ip_port` is commonly 7777 for OCFS2.
`number` must be unique per node (0, 1, 2, …).

copy same `cluster.conf` on every node—the full list of all nodes and their IPs must match on each machine.

Register and configure O2CB
Step 6: Register the cluster
sudo o2cb register-cluster ocfs2

That tells the system which cluster this node belongs to.

Step 7: Configure the driver (one time per node)
[root@jay-db-node01 ~]# sudo /sbin/o2cb.init configure
Configuring the O2CB driver.

This will configure the on-boot properties of the O2CB driver.
The following questions will determine whether the driver is loaded on
boot.  The current values will be shown in brackets ('[]').  Hitting
<ENTER> without typing an answer will keep that current value.  Ctrl-C
will abort.

Load O2CB driver on boot (y/n) [n]: y
Cluster stack backing O2CB [o2cb]:
Cluster to start on boot (Enter "none" to clear) [ocfs2]: ocfs2
Specify heartbeat dead threshold (>=7) [31]: 31
Specify network idle timeout in ms (>=5000) [30000]: 5000
Specify network keepalive delay in ms (>=1000) [2000]:
Specify network reconnect delay in ms (>=2000) [2000]:
Writing O2CB configuration: OK
checking debugfs...
Loading stack plugin "o2cb": OK
Loading filesystem "ocfs2_dlmfs": OK
Creating directory '/dlm': OK
Mounting ocfs2_dlmfs filesystem at /dlm: OK
Setting cluster stack "o2cb": OK
Registering O2CB cluster "ocfs2": OK
Setting O2CB cluster timeouts : OK


Step 8: Start O2CB and check status
[root@jay-db-node01 ~]# sudo o2cb register-cluster ocfs2
[root@jay-db-node01 ~]# sudo systemctl start o2cb
[root@jay-db-node01 ~]# sudo o2cb cluster-status ocfs2
Cluster 'ocfs2' is online

Mount point and format the volume
Step 9: Create the mount directory ( All Nodes)
sudo mkdir /Oradb_data

Step 10: Format the shared disk with OCFS2 (Run it one time on one node only)
[root@jay-db-node01 ~]# sudo mkfs.ocfs2 -L Oradb_data /dev/sdb -N 8
mkfs.ocfs2 1.8.6
Cluster stack: classic o2cb
Label: Oradb_data
Features: sparse extended-slotmap backup-super unwritten inline-data strict-journal-super xattr indexed-dirs refcount discontig-bg
Block size: 4096 (12 bits)
Cluster size: 4096 (12 bits)
Volume size: 2199023255552 (536870912 clusters) (536870912 blocks)
Cluster groups: 16645 (tail covers 2048 clusters, rest cover 32256 clusters)
Extent allocator size: 276824064 (66 groups)
Journal size: 268435456
Node slots: 8
Creating bitmaps: done
Initializing superblock: done
Writing system files: done
Writing superblock: done
Writing backup superblock: 6 block(s)
Formatting Journals: done
Growing extent allocator: done
Formatting slot map: done
Formatting quota files: done
Writing lost+found: done
mkfs.ocfs2 successful

When you see mkfs.ocfs2 successful, the volume is ready. Do not run `mkfs` again on the other nodes.

fstab and mount on every node
Step 11: Add fstab on all nodes
sudo vi /etc/fstab
/dev/sdb /Oradb_data ocfs2     _netdev,defaults   0 0

If the shared disk shows up as a different device name on another node, use a stable name (UUID or `/dev/disk/by-id/...`) so every node points at the same LUN.

Step 12: Mount on all nodes
sudo mount -a
Check with `df -h /Oradb_data` or `mount | grep Oradb_data`

[root@jay-db-node01 ~]# df -h /Oradb_data
Filesystem      Size  Used Avail Use% Mounted on
/dev/sdb        2.0T  4.2G  2.0T   1% /Oradb_data

Tuesday, 20 January 2026

What is the Kube-Scheduler?

kube-scheduler is a watchman. Its primary job is to monitor the API Server for newly created pods that have no nodeName assigned (the "Pending" state). Once it finds one, it evaluates every node in your cluster to find the best possible home based on resources, policies, and hardware constraints.

3-Step Core Workflow
1.Scheduling Queue
Whenever a pod is created, it enters a Pending state and is added to the Scheduling Queue. This isn't a simple FIFO (First-In-First-Out) line; it’s a Priority Queue where pods are sorted based on their PriorityClass. High-priority pods, such as system-critical components, jump to the front of the line to be processed first, while lower-priority pods wait their turn. The scheduler then pulls these pods from the queue one by one to begin the placement process.

2.Filtering:
In this phase, the scheduler runs a series of "Predicates." If a node fails even one of these checks, it is disqualified.
Resource Check (PodFitsResources): Does the node have enough free CPU and Memory to meet the Pod’s requests?
Port Check (PodFitsHostPorts): If a pod requires a specific port on the host (HostPort), is that port already taken by another pod on this node?
Taint/Toleration Check: Nodes can have Taints (repellants). Unless the pod has a matching Toleration, it cannot be scheduled there.
Node Selection: Does the node match the nodeSelector or nodeAffinity labels defined in the Pod spec?

3.Scoring:
After filtering, we might have five nodes that could run the pod. The Scoring phase determines which one should run it. Each node is given a score (usually 0–100) based on several factors:
Least Requested: Favors nodes with more free resources to balance the cluster.
Image Locality: Favors nodes that already have the container image downloaded (speeding up start times).
Affinity/Anti-Affinity: Soft preferences, like "I'd prefer not to be on the same node as other pods from this app for high availability."

The node with the highest score is selected as the "Winner."

Binding: Updating the Cluster State
Once the winner is selected, the scheduler doesn't actually "start" the pod. Instead, it completes a Binding request:
Request to API Server: The scheduler sends a "Binding" object to the kube-apiserver.
API Server Updates etcd: The API Server receives this request, validates it, and updates the Pod's definition in etcd (the cluster's database), setting the nodeName field to the winner's name.
Kubelet Takes Over: The Kubelet (the agent on the worker node) is also watching the API Server. It sees that a pod has been assigned to its node, pulls the image, and starts the container.
    
    

 

Saturday, 17 January 2026

Kubernetes Authorization Modes

In Kubernetes, security is a multi-layered journey. Once a user or service proves their identity—a process known as Authentication—they face a second, more granular challenge: Authorization.

If Authentication asks, "Who are you?", Authorization asks, "What exactly are you allowed to do here?"
In this post, we’ll break down the mechanisms Kubernetes uses to control access and ensure your cluster remains a "Zero Trust" environment.  

1. Node Authorization: 
Node Authorization is a specialized, fixed-purpose authorizer designed specifically for Kubelets. It implements a graph-based check to ensure that a worker node only has access to the resources it absolutely needs to function.

Target: Requests coming from nodes (identified by the system:nodes group and system:node:<nodeName> username).
Technical Logic: It limits a Kubelet's ability to read Secrets, ConfigMaps, and PersistentVolumes. A Kubelet can only access these objects if they are associated with a Pod currently scheduled on that specific node.
Security Impact: This prevents a compromised node from "lateral movement"—it cannot reach out and steal secrets belonging to workloads on other nodes.

2. RBAC: 
Role-Based Access Control (RBAC) is the most common and recommended authorization mechanism. It allows for dynamic, API-driven permission management without requiring an API server restart.

Objects: * Roles/ClusterRoles: Pure sets of permissions (Verbs + Resources + API Groups).
RoleBindings/ClusterRoleBindings: Mapping objects that attach a Subject (User/Group/ServiceAccount) to a Role.
Technical Nuance: RBAC is additive-only. There are no "Deny" rules in RBAC; if no rule grants access, the request is denied by default. It also supports Aggregation, allowing you to combine multiple ClusterRoles into a single "super-role" dynamically.

3. ABAC: Policy-Driven
Attribute-Based Access Control (ABAC) grants access based on a combination of attributes (user, resource, and environment).

Implementation: Unlike RBAC, ABAC policies are defined in a local JSON file on the master node.

Technical Logic: Each line in the policy file is a "Policy Object."For example:
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user": "alice", "namespace": "dev", "resource": "pods", "readonly": true}}

Downside: ABAC is difficult to manage at scale because any change requires a manual update to the file and a restart of the Kube-API server, making it less agile than RBAC.

4. Webhook Authorization: 
Webhook authorization allows Kubernetes to delegate the "Yes/No" decision to a remote HTTP service. This is the ultimate tool for integrating Kubernetes with enterprise-wide security policies.

Flow: When a request arrives, the API server sends a SubjectAccessReview (a JSON-serialized object) to an external REST endpoint.
 Technical Payload: The payload includes the username, groups, and the specific resource/verb requested. The remote service responds with an allowed: true or false status. 

Use Cases: * Integrating with Open Policy Agent (OPA) for complex logic.

5. AlwaysAllow:
As the name suggests, the AlwaysAllow mode grants every request, regardless of who is asking or what they are trying to do. It completely bypasses all security checks.

Technical Logic: It returns allowed: true for every single API call.
Use Cases: * Local Development: Used in very restricted, single-node local environments (like early-stage minikube setups) where security isn't a concern.
Unit Testing: Used by developers testing API server extensions where they want to isolate the logic from authorization interference.
Risk: Enabling this in a production cluster is a critical security failure. It effectively turns off the cluster's "immune system," allowing any unauthenticated "system:anonymous" user to delete the entire cluster.

6. AlwaysDeny:
The AlwaysDeny mode does exactly the opposite: it rejects every single request.

Technical Logic: It returns allowed: false for everything.
Use Cases: * Security Hardening: It is often used at the very end of a list of authorization modes. If the request doesn't match a Node rule, an RBAC rule, or a Webhook rule, it hits the "final wall" and is rejected.
Emergency Lockdown: In extreme scenarios, an administrator could theoretically set this to prevent any further changes to the cluster state during an active breach investigation.
Nuance: Even with AlwaysDeny, the API server may still allow certain "discovery" endpoints (like /healthz) depending on the version and configuration, but for all intents and purposes, the cluster becomes a "read-only/no-access" vault.
    
        

Saturday, 10 January 2026

Kubernetes API: Understanding apiVersion

apiVersion field is the first line of every manifest. While it may seem like a static piece of boilerplate, it is actually the most important instruction you give to the API server. It defines the schema, the validation rules, and the stability of the resource are about to create.

Kubernetes organizes its thousands of parameters into API Groups. The apiVersion string tells the cluster which "folder" and "version" of the API to look in.

There are two distinct patterns for these values:
1. The Core Group
These are the foundational objects of Kubernetes. Because they have existed since the beginning, they do not belong to a named group.
    Format: v1
    Resources: Pod, Service, Namespace, Node, ConfigMap, Secret.
    Example: 
    YAML
    apiVersion: v1
    kind: Service

2. Named Groups
As Kubernetes evolved, new functionality was added via specialized groups. These follow a "Group/Version" structure.
    Format: group.k8s.io/version
    Resources: Deployments, Ingress, CronJobs.
    Example:
    YAML
    apiVersion: apps/v1
    kind: Deployment

The Stability Lifecycle
Version     Stability           Description
v1alpha1    Experimental        May contain bugs. Can be dropped in future releases without warning.
v1beta1     Prerelease          Feature-complete and tested. Safe for non-critical environments.
v1          Stable              Production-ready.   

 
Many resources have migrated from "Beta" to "Stable" over the last few years. Here is the current standard mapping for common resources:
    Workloads: apps/v1 (Deployment, StatefulSet, DaemonSet)
    Batch: batch/v1 (Job, CronJob)
    Networking: networking.k8s.io/v1 (Ingress, NetworkPolicy)
    RBAC: rbac.authorization.k8s.io/v1 (Role, ClusterRole)

# See all resources and their associated API versions
kubectl api-resources

# List all enabled API versions on the server
kubectl api-versions