Series: Kubernetes on AKS: From Zero to Production Workloads

Part 1: Workspace, Tools and Azure Sign-In

Environment: Ubuntu on WSL, VS Code terminal, Azure CLI, kubectl and Git

Before deploying workloads to Kubernetes, there is some groundwork to do. A reliable environment needs more than a cluster: it needs a structured project directory, version control, the right command-line tools, authenticated access to Azure, and the necessary resource providers.

In this first part of my nine-part series, I'll walk through how I prepared the environment for a hands-on Azure Kubernetes Service (AKS) lab. I'll cover the project workspace, Git initialization, Azure CLI installation, Azure authentication, Kubernetes command-line tools, and Azure resource provider registration. I'll also share an installation error I encountered, how I investigated it, and the workaround that allowed me to continue.

1. Creating the project workspace

I started by creating a dedicated directory for the lab and navigating into it.

mkdir -p /mnt/c/Users/Admin/Desktop/labs/aks-kubernetes-lab cd /mnt/c/Users/Admin/Desktop/labs/aks-kubernetes-lab pwd 

Here's what each command does:

  • mkdir -p creates the project directory, including any missing parent directories.
  • cd moves into the directory.
  • pwd prints the current working directory so we can verify the location.

The terminal returned:

/mnt/c/Users/Admin/Desktop/labs/aks-kubernetes-lab 

Confirming the working directory matters because subsequent commands create files and perform Git operations relative to that location.

A dedicated workspace keeps the project's documentation, Kubernetes manifests, and configuration organized as the lab grows.

part-01-workspace-creation.png

2. Initializing Git

With the workspace ready, I initialized a Git repository using main as the initial branch.

git init -b main 

The terminal confirmed:

Initialized empty Git repository in /mnt/c/Users/Admin/Desktop/labs/aks-kubernetes-lab/.git/ 

git init

Git provides version control, allowing us to track changes, review previous versions, and maintain a history of the files created throughout the project.

The -b main option establishes main as the initial branch.

At this point, the repository existed locally. It had not yet been connected to a remote GitHub repository.

3. Creating the initial project structure

Next, I created a directory to hold the Kubernetes manifests.

mkdir -p manifests 

I then created an initial README.md file:

printf '# Kubernetes on AKS\n\nProduction Kubernetes workloads on Azure Kubernetes Service, built as a hands-on lab.\n' > README.md 

To inspect the file, I ran:

cat README.md 

The output was:

# Kubernetes on AKS Production Kubernetes workloads on Azure Kubernetes Service, built as a hands-on lab. 

This README was intentionally minimal. It established the repository's entry point, while the manifests/ directory provided a dedicated location for Kubernetes YAML files.

The initial project structure looked like this:

aks-kubernetes-lab/ ├── manifests/ └── README.md 

This represents the initial structure, not the final repository layout.

part-01-initial-project-structure

4. Staging the README

Before creating the first commit, I staged the README and checked the repository status.

git add README.md git status 

Git reported:

On branch main No commits yet Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: README.md 

git status

The output confirmed that README.md was staged and ready to be included in a commit.

Git's staging area lets us choose which changes belong in a commit. This is useful when a project contains multiple modifications but we want to record only a specific set of changes.

5. Adding .gitignore and creating the first commit

Before committing the initial files, I created a .gitignore file.

printf 'lab.env\n*.log\n' > .gitignore 

Its contents were:

lab.env *.log 

The lab.env rule tells Git to ignore a file named lab.env, while *.log ignores files ending in .log.

This is a useful precaution when working with cloud infrastructure. Environment files may contain configuration values that should not be published, and log files can add unnecessary clutter to a repository.

Important: .gitignore does not remove files that have already been committed or staged. It is a preventive measure, not a replacement for proper secret management.

I staged the files and created the initial commit:

git add README.md .gitignore git commit -m "chore: initialise AKS lab workspace" 

Git confirmed the commit:

[main (root-commit) 7bdb9aa] chore: initialise AKS lab workspace 2 files changed, 5 insertions(+) create mode 100644 .gitignore create mode 100644 README.md 

This established the first checkpoint in the repository's history. Subsequent changes could now be recorded as separate commits.

initial-git-commit

6. Installing Azure CLI

The next step was to install the Azure command-line interface (Azure CLI).

Azure CLI allows us to manage Azure resources from a terminal. It is particularly useful for repeatable infrastructure workflows, where commands can be documented and reused instead of relying exclusively on the Azure portal.

I ran the installation command provided by the lab:

curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash 

part-01-azure-cli-installation

The command downloads and executes Microsoft's installation script for Debian-based Linux environments. Because it runs with elevated privileges, it is important to use a trusted installation source and understand what the command does.

The terminal showed the package repositories being updated and Azure CLI being installed.

I then verified the installation:

az version 

The output included:

{ "azure-cli": "2.91.0", "azure-cli-core": "2.91.0", "azure-cli-telemetry": "1.1.0" } 

This confirmed that Azure CLI was installed and available from the terminal.

az version

7. Signing in to Azure

With Azure CLI installed, I authenticated using device-code sign-in.

az login --use-device-code 

azure-device-login

The CLI instructed me to open Microsoft's device-login page in a browser and enter the displayed code. After completing the browser authentication, I selected the available subscription.

The terminal showed the selected subscription as Azure subscription 1 under Default Directory.

Device-code authentication is useful when the terminal cannot conveniently open a browser or when authentication needs to be completed in a separate browser session.

Verifying the active account

I checked the active Azure account using:

az account show --output table 

azure-account-verification

The output displayed account information, including the subscription name, state, and tenant details.

This verification is important because the subscription selected in Azure CLI determines where subsequent Azure commands will operate. Accidentally using the wrong subscription can result in resources being created in the wrong environment.

Security note: Before publishing terminal screenshots, redact device codes, access tokens, credentials, and any identifiers you don't want to expose.

8. Installing Kubernetes command-line tools

Azure CLI manages Azure resources, but we also need kubectl to interact with Kubernetes.

kubectl is the Kubernetes command-line client. It allows us to inspect resources, apply manifests, examine workload status, and communicate with the Kubernetes API when a cluster is available and the appropriate credentials and permissions are configured.

The lab's initial installation command was:

sudo az aks install-cli 

Troubleshooting: The default installation path failed

The command encountered an error:

Connection error while attempting to download client ([Errno 2] No such file or directory: '/usr/local/bin/kubectl') 

The terminal also showed that /usr/local/bin existed.

This was a useful reminder that an installation command can fail at its target path even when Azure CLI itself is working. Rather than repeatedly retrying the same command, I inspected the directory and switched to a user-local installation location.

First, I checked the directory:

ls -ld /usr/local/bin 

Then I created a directory under my home folder:

mkdir -p ~/.local/bin 

I reran the installation with explicit paths:

az aks install-cli \ --install-location ~/.local/bin/kubectl \ --kubelogin-install-location ~/.local/bin/kubelogin 

This instructed the installer to place kubectl and kubelogin in my user-local binary directory.

The installer completed the downloads and advised that ~/.local/bin needed to be included in PATH so the shell could find the commands.

Adding the installation directory to PATH

I added the directory to my Bash configuration:

echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc 

Then I reloaded the configuration:

source ~/.bashrc 

Finally, I verified the Kubernetes client installation:

kubectl version --client 

The terminal returned:

Client Version: v1.37.1 Kustomize Version: v5.8.1 

This confirmed that the kubectl client was installed and available from the shell.

What resolved the problem?

The workaround used a directory within my home folder rather than the original default installation location. Updating PATH then allowed the shell to locate the downloaded binaries.

The failure occurred during local tooling setup, before a Kubernetes cluster was involved. Distinguishing local installation problems from cluster or workload problems makes troubleshooting more systematic.

kubectl-install

9. Registering Azure resource providers

Before creating Azure resources, the subscription may need the relevant resource providers registered.

A resource provider exposes the management operations for a category of Azure resources. For this lab, I registered four providers:

az provider register --namespace Microsoft.ContainerService az provider register --namespace Microsoft.Compute az provider register --namespace Microsoft.Network az provider register --namespace Microsoft.Storage 

These providers correspond to the services used throughout the lab:

Resource provider Purpose
Microsoft.ContainerService AKS and related container-service management
Microsoft.Compute Virtual machines and compute resources
Microsoft.Network Networking resources, including virtual networks and load balancers
Microsoft.Storage Azure storage resources

Registering a provider does not create an AKS cluster or provision the associated resources. It enables the subscription to use the relevant provider's operations.

Verifying registration

I checked the registration state of the AKS provider:

az provider show \ --namespace Microsoft.ContainerService \ --query registrationState \ --output tsv 

The result was:

Registered 

registered

This confirmed that Microsoft.ContainerService was registered. The screenshot documents the verification of this provider; it does not independently confirm the registration state of all four providers.

10. Preparing the lab environment

The lab used an environment file to keep its configuration values consistent across subsequent commands.

cat << 'EOF' > lab.env export RESOURCE_GROUP=rg-aks-lab export LOCATION=westeurope export CLUSTER_NAME=aks-lab export NODE_SIZE=Standard_D2s_v3 EOF 

I loaded the variables into the current shell:

source lab.env 

Then I checked their values:

echo "$RESOURCE_GROUP $LOCATION $CLUSTER_NAME $NODE_SIZE" 

The terminal returned:

rg-aks-lab westeurope aks-lab Standard_D2s_v3 

list

Using variables avoids repeatedly typing the same resource names and configuration values throughout a lab. It also reduces the chance of accidentally using inconsistent names in later commands.

The values describe the intended lab configuration; they do not mean the AKS cluster has already been created.

Security reminder: lab.env is included in .gitignore. Keep credentials and secrets out of source control, and check the repository's status before committing changes.

Key takeaways

  • A dedicated workspace and Git history provide a maintainable starting point for infrastructure projects.
  • .gitignore helps prevent selected local files from being added to the repository, but it does not replace proper secret management.
  • Azure CLI and kubectl have different roles: one manages Azure resources, while the other interacts with Kubernetes.
  • When an installer fails at its default path, inspecting the environment and selecting a suitable installation location can provide a practical workaround.
  • Always verify the active Azure account and subscription before creating or modifying resources.
  • Registering a resource provider enables its operations; it does not create resources by itself.

What's next?

In Part 2, I'll continue with the next stage of the lab: provisioning and configuring the Azure Kubernetes Service infrastructure, following the lab guide.

We'll move from preparing the local environment to establishing the Azure infrastructure on which the Kubernetes workloads will run.

This is the foundation for the remaining parts of the series, covering Kubernetes workloads, networking, configuration, storage, automation, scaling, cost optimization, and cleanup.

This article documents the commands and outcomes captured during the lab. Installation results and version numbers reflect the recorded environment and may differ on other systems. Review commands, permissions, and potential Azure charges before running them in your own subscription.