Level: Intermediate
Prerequisites: Basic knowledge of Kubernetes and containers
Table of Contents
- Course Overview
- Course Introduction
- Using Storage in Kubernetes
- Multi-container Pod Use Cases
- Securing Applications with Service Accounts
- Bringing It All Together — Final Demo
- Reference Tables
- Architecture Diagrams
1. Course Overview
This course goes beyond Kubernetes basics to tackle real-world topics:
- Persistent storage: storage solutions, integration with high-performance and high-availability storage services
- Multi-container Pods: init containers and all sidecar patterns
- Security: securing applications running in Kubernetes
By the end of this course, you will have the skills needed to work with Kubernetes applications in production.
2. Course Introduction
Agenda
| Module | Content |
|---|---|
| Module 3 | Storage — volumes, persistence, PV/PVC, CSI, static and dynamic provisioning |
| Module 4 | Multi-container Pods — init containers, sidecar, adapter, ambassador |
| Module 5 | Service Accounts — AuthN/AuthZ, RBAC |
| Module 6 | Final demo integrating all concepts |
Recommended prerequisites
Before starting, it is recommended to have completed at least one of the following courses:
- Getting Started with Kubernetes
- Kubernetes for Developers: Core Concepts
3. Using Storage in Kubernetes
3.1 Storage Overview
Storage is a critical topic for production applications. Most business-critical applications rely on data that must be available and protected.
Historical context (before containers):
- On-premises deployment with physical servers
- Dedicated storage systems (EMC, NetApp, etc.)
- High-performance and high-availability volumes exposed as local disks to servers
- These systems handled replication, failover, and encryption automatically
With Kubernetes:
- Kubernetes does not reinvent the storage wheel
- The model: let storage systems do their magic, Kubernetes simply consumes them
- A plugin (CSI driver) connects the external storage system to the Kubernetes cluster
3.2 Decoupling the Data Lifecycle
The problem with the base container model
Container started → Data written → Container deleted/crashed → Data LOST
In the default container model, the data lifecycle is coupled to the container lifecycle. This is acceptable for stateless applications but unacceptable for stateful applications.
Analogy: It is like storing your photos only on your phone, without cloud backup. If the phone is lost, so are the photos.
The solution: decoupling lifecycles
Application (container) ←→ Volume (external storage)
↑
INDEPENDENT lifecycle
Benefits:
- Data survives container death
- Data sharing between containers
- Access from multiple pods (depending on access mode)
3.3 The Kubernetes PersistentVolume Subsystem
graph LR
A[External storage system<br/>50Gi volume] -->|CSI Plugin| B[PersistentVolume PV<br/>Kubernetes object]
B -->|Binding| C[PersistentVolumeClaim PVC<br/>Storage request]
C -->|Referenced in| D[Pod Spec<br/>volumes + volumeMounts]
D -->|Mounted in| E[Container<br/>/data]
Kubernetes API storage objects
| Object | Role | Scope |
|---|---|---|
StorageClass | Defines a storage class/tier + the provisioner | Cluster |
PersistentVolume (PV) | Represents an external volume in Kubernetes | Cluster |
PersistentVolumeClaim (PVC) | Storage request made by an application | Namespace |
Access Modes
| Mode | Abbreviation | Description |
|---|---|---|
ReadWriteOnce | RWO | Read/write by a single node |
ReadOnlyMany | ROX | Read-only by multiple nodes |
ReadWriteMany | RWX | Read/write by multiple nodes |
YAML — PersistentVolume (static provisioning)
apiVersion: v1
kind: PersistentVolume
metadata:
name: ps-pv
spec:
capacity:
storage: 50Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
csi:
driver: pd.csi.storage.gke.io
volumeHandle: projects/PROJECT_ID/zones/ZONE/disks/ps-vol
YAML — PersistentVolumeClaim
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: ps-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 50Gi
storageClassName: "" # empty = manual binding to an existing PV
YAML — Pod using a PVC
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
volumes:
- name: data-vol
persistentVolumeClaim:
claimName: ps-pvc
containers:
- name: app
image: nginx
volumeMounts:
- mountPath: /data
name: data-vol
PVC lifecycle
stateDiagram-v2
[*] --> Pending: PVC created
Pending --> Bound: Available PV found / created
Bound --> Released: Pod deleted, PVC deleted
Released --> Available: reclaimPolicy=Recycle
Released --> [*]: reclaimPolicy=Delete
Released --> Released: reclaimPolicy=Retain (manual intervention)
3.4 The Container Storage Interface (CSI)
History: In-tree vs Out-of-tree
graph TB
subgraph "Old model (In-tree)"
K1[Kubernetes Core Code] --> D1[EMC Driver]
K1 --> D2[NetApp Driver]
K1 --> D3[AWS EBS Driver]
end
subgraph "New CSI model (Out-of-tree)"
K2[Kubernetes Core Code] -->|Standard interface| CSI[CSI Layer]
CSI --> P1[EMC CSI Plugin]
CSI --> P2[NetApp CSI Plugin]
CSI --> P3[AWS EBS CSI Plugin]
end
Problems with the in-tree model:
- Third-party code had to be open source (Apache 2.0)
- Bug fixes were tied to the Kubernetes release cycle
- Kubernetes maintainers had to manage third-party code
Benefits of CSI:
- Vendors can publish patches independently
- No open-source license constraint
- Standardized interface → portability across orchestrators (K8s, Mesos, etc.)
3.5 Static Provisioning
Flow:
- Administrator manually creates a volume on the storage system
- Administrator creates a
PersistentVolumeobject that maps that volume - Developer creates a
PersistentVolumeClaim - Kubernetes automatically binds the PVC to the matching PV
- The Pod references the PVC
Limitations: Does not scale in large environments — manual management for every volume.
3.6 Dynamic Provisioning
Flow:
- Administrator creates a
StorageClass(once only) - Developer creates a
PersistentVolumeClaimreferencing the StorageClass - Kubernetes automatically creates the PV and volume on the backend
- The Pod uses the PVC
YAML — StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ps-sc-fast
annotations:
storageclass.kubernetes.io/is-default-class: "true"
provisioner: pd.csi.storage.gke.io
parameters:
type: pd-ssd
reclaimPolicy: Delete
allowVolumeExpansion: true
YAML — PVC with StorageClass (dynamic provisioning)
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: ps-pvc-dynamic
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: ps-sc-fast # references the StorageClass
Advantage: The StorageClass automatically creates volumes on demand — scalable and efficient.
3.7 Advanced Volume Features
Raw Block Volumes
Some applications (notably databases) write directly to unformatted raw volumes for better performance.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: block-pvc
spec:
accessModes:
- ReadWriteOnce
volumeMode: Block # <-- raw block (not Filesystem)
resources:
requests:
storage: 10Gi
---
apiVersion: v1
kind: Pod
metadata:
name: block-pod
spec:
volumes:
- name: block-vol
persistentVolumeClaim:
claimName: block-pvc
containers:
- name: app
image: ubuntu
volumeDevices: # <-- volumeDevices (not volumeMounts)
- name: block-vol
devicePath: /dev/block
Volume Clones
Clone an existing volume to create an identical new PVC:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: cloned-pvc
spec:
dataSource:
name: source-pvc # source PVC to clone
kind: PersistentVolumeClaim
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
Volume Snapshots
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: my-snapshot
spec:
volumeSnapshotClassName: csi-hostpath-snapclass
source:
persistentVolumeClaimName: my-pvc
3.8 Summary — Storage
graph TB
EXT[External storage system<br/>cloud or on-prem] -->|CSI Plugin| K8S
subgraph K8S [Kubernetes Cluster]
PV[PersistentVolume PV]
PVC[PersistentVolumeClaim PVC]
SC[StorageClass]
POD[Pod]
SC -->|creates automatically| PV
PVC -->|bind| PV
POD -->|references| PVC
end
Key points:
- External storage exists outside of Kubernetes
- Each system has its CSI plugin
- PV = Kubernetes representation of an external volume
- PVC = application storage request
- StorageClass = automatic and dynamic provisioning
- All containers in a Pod can share the Pod’s volumes
4. Multi-container Pod Use Cases
4.1 Pod Theory
Why Pods?
The Pod is the smallest deployable unit in Kubernetes. You do not deploy containers directly — Kubernetes requires them to be encapsulated in Pods.
What Pods provide to containers:
| Feature | Description |
|---|---|
| Probes | startup probe, readiness probe, liveness probe |
| Affinities | node affinity, pod affinity, anti-affinity |
| Policies | restartPolicy, terminationGracePeriodSeconds |
| Co-scheduling | guarantees multiple containers are on the same node |
| Shared network namespace | all containers in a Pod share the same IP |
| Shared volumes | volumes are accessible by all containers in the Pod |
Internal Pod architecture
graph TB
subgraph POD [Pod — Shared execution environment]
subgraph NET [Shared network namespace]
C1[Main container<br/>app]
C2[Sidecar container<br/>helper]
IC[Init Container<br/>runs before]
end
VOL[Shared volume<br/>emptyDir / PVC]
C1 <-->|mount| VOL
C2 <-->|mount| VOL
IC -->|prepares| VOL
end
POD -->|unique IP| NET2[Cluster network]
Main rule: One container = one responsibility. Initialization and integration logic goes in separate containers.
4.2 The Init Container Pattern
Concept
An init container is a special container that:
- Runs before the main container
- Runs once and must complete successfully
- There can be multiple init containers (they run sequentially)
- The main container starts only if all init containers succeed
sequenceDiagram
participant K as Kubernetes
participant I1 as Init Container 1
participant I2 as Init Container 2
participant A as App Container
K->>I1: Start
I1-->>K: Completes (exit 0)
K->>I2: Start
I2-->>K: Completes (exit 0)
K->>A: Start
A-->>K: Running...
Typical use cases
- Clone a Git repository into a shared volume before the web server starts
- Wait for an API or database to be available
- Initialize permissions on files/directories
- Prepare datasets
Analogy: The init container is like a constructor in a programming language — it prepares the environment before the main code runs.
YAML — Init Container
apiVersion: v1
kind: Pod
metadata:
name: init-demo
spec:
# Volume shared between init container and app container
volumes:
- name: web-content
emptyDir: {}
# Init container: clones a Git repo
initContainers:
- name: git-cloner
image: alpine/git
command:
- git
- clone
- https://github.com/example/ps-web.git
- /web-content
volumeMounts:
- name: web-content
mountPath: /web-content
# Main container: serves the cloned content
containers:
- name: web-server
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: web-content
mountPath: /usr/share/nginx/html
YAML — Init Container waiting for a service
initContainers:
- name: wait-for-api
image: busybox
command:
- sh
- -c
- |
until wget -q --spider http://my-api-service:8080/health; do
echo "Waiting for API..."
sleep 5
done
echo "API is ready!"
4.3 The Sidecar Pattern
Concept
A sidecar is a container that runs in parallel with the main container, throughout the lifetime of the Pod. It is the most generic pattern — adapter and ambassador are specialized variants of it.
graph LR
subgraph POD [Pod]
MAIN[Main container<br/>nginx / app] <-->|Shared volume| VOL[emptyDir]
SIDE[Sidecar<br/>git-sync] <-->|Shared volume| VOL
end
SIDE -->|periodic sync| GIT[GitHub Repo]
Difference from Init Container
| Criterion | Init Container | Sidecar |
|---|---|---|
| Timing | Before the main app | In parallel with the app |
| Duration | Runs once and terminates | Runs continuously |
| Usage | Initialization | Continuous integration |
YAML — Sidecar (continuous git-sync)
apiVersion: v1
kind: Pod
metadata:
name: sidecar-demo
spec:
volumes:
- name: web-content
emptyDir: {}
containers:
# Main container
- name: web-server
image: nginx
volumeMounts:
- name: web-content
mountPath: /usr/share/nginx/html
# Sidecar: continuous sync from Git
- name: git-sync
image: k8s.gcr.io/git-sync:v3.1.6
env:
- name: GIT_SYNC_REPO
value: https://github.com/example/ps-web.git
- name: GIT_SYNC_DEST
value: /web-content
- name: GIT_SYNC_PERIOD
value: "30" # sync every 30 seconds
volumeMounts:
- name: web-content
mountPath: /web-content
4.4 The Adapter Pattern
Concept
The adapter is a specialized sidecar that transforms the format of data (metrics, logs) from the main application to a format expected by external tools.
Typical use case: Prometheus expects metrics in a specific format. If your application exposes metrics in a different format, an adapter sidecar handles the translation.
graph LR
subgraph POD [Pod]
APP[App Container<br/>native format metrics] -->|internal port| ADP[Adapter Container<br/>transforms format]
end
ADP -->|Prometheus format| PROM[Prometheus Server]
YAML — Adapter Pattern
apiVersion: v1
kind: Pod
metadata:
name: adapter-demo
spec:
containers:
# Main container: exposes metrics in a custom format
- name: web-app
image: nigelpoulton/nginxadapter:1.0
ports:
- containerPort: 8080
# Adapter sidecar: transforms metrics for Prometheus
- name: prometheus-adapter
image: nginx/nginx-prometheus-exporter:0.4.2
args:
- -nginx.scrape-uri=http://localhost:8080/nginx_status
ports:
- containerPort: 9113 # Prometheus port
Best practice: List the main container first in the containers array — it receives the focus of kubectl exec and kubectl logs commands by default.
4.5 The Ambassador Pattern
Concept
The ambassador is a specialized sidecar that acts as a proxy between the main container and external systems. The main container does not know the details of external connections — it communicates only with the ambassador on localhost.
Analogy: Like a political ambassador who manages relations with a foreign nation on behalf of their government — the president (main container) does not need to know the diplomatic protocol details.
graph LR
subgraph POD [Pod]
APP[App Container<br/>talks to localhost:9000] -->|localhost| AMB[Ambassador Container<br/>intelligent proxy]
end
AMB -->|manages certs, auth, routing| EXT[External API / External Service]
Benefits
- The main container does not change when the external API changes (address, port, certificates)
- Connection logic is centralized in the ambassador
- Simplifies testing (mock the ambassador)
YAML — Ambassador Pattern
apiVersion: v1
kind: Pod
metadata:
name: ambassador-demo
spec:
containers:
# Main container: connects to localhost:9000
- name: app
image: nigelpoulton/app:1.0
env:
- name: AMBASSADOR_URL
value: http://localhost:9000
# Ambassador sidecar: proxy to external API
- name: ambassador
image: nigelpoulton/ambassador:1.0
ports:
- containerPort: 9000
env:
- name: EXTERNAL_API_URL
value: https://external-api.example.com
- name: API_KEY
valueFrom:
secretKeyRef:
name: api-secrets
key: api-key
4.6 Summary — Multi-container Pods
graph TB
subgraph PATTERNS [Multi-container Pod Patterns]
INIT[Init Container<br/>🔵 runs BEFORE the app<br/>once only<br/>initialization]
SC[Generic Sidecar<br/>🟢 runs IN PARALLEL<br/>continuously<br/>continuous integration]
AD[Adapter<br/>🟡 Sidecar variant<br/>transforms data<br/>metrics / logs]
AM[Ambassador<br/>🔴 Sidecar variant<br/>proxy to the outside<br/>connection abstraction]
end
INIT -.->|Precondition for| SC
| Pattern | Type | Timing | Primary usage |
|---|---|---|---|
| Init Container | Special (non-sidecar) | Before the app | Initialization, waiting for dependencies |
| Sidecar | Generic sidecar | Continuous parallel | Content sync, log forwarding |
| Adapter | Specialized sidecar | Continuous parallel | Format transformation (metrics/logs) |
| Ambassador | Specialized sidecar | Continuous parallel | Proxy to external systems |
5. Securing Applications with Service Accounts
5.1 Kubernetes AuthN and AuthZ
Overview
In Kubernetes, everything goes through the API server — both kubectl commands from humans and requests from applications in Pods.
graph LR
U[Human user<br/>kubectl] -->|User Account<br/>TLS certificates| API[API Server]
APP[Application in Pod] -->|Service Account<br/>JWT token| API
API -->|AuthN| AUTHN[Who are you?<br/>Authentication]
AUTHN -->|AuthZ| AUTHZ[What are you allowed to do?<br/>Authorization RBAC]
Two types of secured entities:
| Type | Entity | Managed by |
|---|---|---|
| User Account | Humans, external tools (kubectl) | Outside Kubernetes (identity management) |
| Service Account | Applications in Pods | Kubernetes (native API objects) |
Principle of least privilege: Each entity should have only the minimum permissions necessary for its work.
5.2 Discovering Service Accounts
Default behavior
- Every namespace automatically has a
defaultService Account - Every Pod is automatically associated with the
defaultService Account of its namespace (if not specified) - An admission controller watches Pod creation and assigns the default SA if absent
- SA tokens are automatically mounted in the Pod
Inspecting Service Accounts
# List service accounts
kubectl get serviceaccounts
# Details of a service account
kubectl describe serviceaccount default
# See the SA of a Pod
kubectl get pod my-pod -o yaml | grep serviceAccountName
Service Account structure
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-service-account
namespace: default
5.3 Using Service Accounts
Create a Service Account and configure RBAC
# 1. Create the Service Account
apiVersion: v1
kind: ServiceAccount
metadata:
name: service-reader
namespace: default
---
# 2. Create a Role (permissions)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: service-reader-role
namespace: default
rules:
- apiGroups: [""]
resources: ["services"]
verbs: ["get", "list", "watch"]
---
# 3. Bind the Role to the Service Account (RoleBinding)
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: service-reader-binding
namespace: default
subjects:
- kind: ServiceAccount
name: service-reader
namespace: default
roleRef:
kind: Role
name: service-reader-role
apiGroup: rbac.authorization.k8s.io
Assigning a Service Account to a Pod
apiVersion: v1
kind: Pod
metadata:
name: my-app-pod
spec:
serviceAccountName: service-reader # <-- specify the SA
containers:
- name: app
image: my-app:1.0
Useful commands
# Create an SA via CLI
kubectl create serviceaccount service-reader
# Check the rights of an SA
kubectl auth can-i list services --as=system:serviceaccount:default:service-reader
5.4 Summary — Service Accounts
- Everything goes through the API server (AuthN → AuthZ)
- Humans use User Accounts (managed outside Kubernetes)
- Applications in Pods use Service Accounts (managed inside Kubernetes)
- RBAC is the standard authorization plugin (enabled by default on most clusters)
- By default, Pods receive the
defaultSA which has very limited permissions - In production: create dedicated SAs with the principle of least privilege
6. Bringing It All Together — Final Demo
The final demo combines all course concepts in a single multi-resource YAML file (separated by ---):
# finale-eks-disk.yml — Complete example integrating everything
# 1. StorageClass — dynamic provisioning
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ps-sc-final
provisioner: ebs.csi.aws.com
parameters:
type: gp2
reclaimPolicy: Delete
---
# 2. PersistentVolumeClaim
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: app-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: ps-sc-final
resources:
requests:
storage: 10Gi
---
# 3. ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
name: app-sa
namespace: default
---
# 4. RBAC Role
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: app-role
namespace: default
rules:
- apiGroups: [""]
resources: ["services", "pods"]
verbs: ["get", "list"]
---
# 5. RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: app-role-binding
namespace: default
subjects:
- kind: ServiceAccount
name: app-sa
roleRef:
kind: Role
name: app-role
apiGroup: rbac.authorization.k8s.io
---
# 6. Pod — integrates everything
apiVersion: v1
kind: Pod
metadata:
name: final-demo-pod
labels:
app: final-demo
spec:
serviceAccountName: app-sa # Service Account
volumes:
- name: persistent-data
persistentVolumeClaim:
claimName: app-pvc # PVC for persistent data
- name: shared-content
emptyDir: {} # Temporary shared volume
# Init Container — prepares the environment
initContainers:
- name: initializer
image: busybox
command: ["sh", "-c", "echo 'Init complete' > /shared/ready.txt"]
volumeMounts:
- name: shared-content
mountPath: /shared
containers:
# Main container
- name: app
image: nginx:1.21
ports:
- containerPort: 80
volumeMounts:
- name: persistent-data
mountPath: /data # Persistent data
- name: shared-content
mountPath: /shared # Shared data
# Ambassador Sidecar — proxy to external API
- name: ambassador
image: envoyproxy/envoy:v1.18.0
ports:
- containerPort: 9000
volumeMounts:
- name: shared-content
mountPath: /shared
To deploy:
kubectl apply -f finale-eks-disk.yml
# Verify
kubectl get pods
kubectl get pvc
kubectl describe pod final-demo-pod
7. Reference Tables
Kubernetes volume types
| Type | Persistence | Usage | Notes |
|---|---|---|---|
emptyDir | Pod lifetime | Sharing between containers | Deleted when the Pod terminates |
hostPath | Node lifetime | Access to node files | Not recommended in production |
configMap | Permanent (config) | Configuration injection | Generally read-only |
secret | Permanent (secret) | Passwords, tokens, certs | Base64 encoded |
persistentVolumeClaim | Permanent | Persistent application data | Recommended for production |
nfs | Permanent | Network share | ReadWriteMany possible |
csi | Permanent | Volumes via CSI drivers | Modern standard |
Multi-container Pod patterns
| Pattern | Container | Role | Data sharing |
|---|---|---|---|
| Init | initContainers[] | Initializes before the app | Shared volume with the app |
| Sidecar | containers[] | Continuous helper | Shared volume or localhost |
| Adapter | containers[] | Transforms outgoing data | localhost (internal port) |
| Ambassador | containers[] | Proxies external connections | localhost (internal port) |
Essential kubectl commands — Volumes
# PersistentVolumes
kubectl get pv
kubectl describe pv <pv-name>
# PersistentVolumeClaims
kubectl get pvc
kubectl describe pvc <pvc-name>
# StorageClasses
kubectl get storageclass
kubectl get sc
# Inspect volumes of a Pod
kubectl describe pod <pod-name>
kubectl get pod <pod-name> -o yaml | grep -A 20 volumes:
Essential kubectl commands — Multi-container Pods
# Logs of the main container
kubectl logs <pod-name>
# Logs of a specific container
kubectl logs <pod-name> -c <container-name>
# Logs of the init container
kubectl logs <pod-name> -c <init-container-name>
# Exec into a specific container
kubectl exec -it <pod-name> -c <container-name> -- /bin/sh
# View all containers of a Pod
kubectl get pod <pod-name> -o jsonpath='{.spec.containers[*].name}'
Essential kubectl commands — Service Accounts
# List Service Accounts
kubectl get sa
kubectl get serviceaccounts
# View details
kubectl describe sa <sa-name>
# Check permissions
kubectl auth can-i <verb> <resource> --as=system:serviceaccount:<namespace>:<sa-name>
# Example
kubectl auth can-i list services --as=system:serviceaccount:default:my-sa
8. Architecture Diagrams
Volume types — Overview
graph TB
subgraph EPHEMERAL [Ephemeral volumes - tied to Pod lifecycle]
ED[emptyDir<br/>empty at startup<br/>shared between containers]
HP[hostPath<br/>file/folder on Node<br/>⚠️ not recommended in prod]
CM[configMap<br/>configuration data]
SEC[secret<br/>sensitive data]
end
subgraph PERSISTENT [Persistent volumes - survive the Pod]
PVC2[PersistentVolumeClaim<br/>standard interface<br/>✅ recommended]
NFS[nfs<br/>network share<br/>RWX possible]
CSI2[csi<br/>Container Storage Interface<br/>modern standard]
end
PVC2 -->|bind| PV[PersistentVolume PV]
PV -->|CSI Driver| BACK[Backend: AWS EBS / GCE PD / Azure Disk / NFS / etc.]
Data sharing flow between containers
sequenceDiagram
participant IC as Init Container
participant VOL as Shared volume (emptyDir)
participant APP as App Container
participant SC as Sidecar Container
Note over IC: Initialization phase
IC->>VOL: Writes initial data
IC-->>APP: Completes (exit 0)
Note over APP,SC: Execution phase (parallel)
APP->>VOL: Reads/writes app data
SC->>VOL: Reads app data
SC-->>APP: Transforms/exposes (via localhost)
Complete architecture — PV/PVC/StorageClass
graph LR
subgraph ADMIN [Kubernetes Administrator]
SC3[StorageClass<br/>once]
end
subgraph DEV [Developer]
PVC3[PersistentVolumeClaim<br/>spec: 10Gi]
PODSPEC[Pod Spec<br/>volumes + volumeMounts]
end
subgraph K8S [Kubernetes automatic]
PROV[CSI Provisioner]
PV3[PersistentVolume<br/>10Gi created automatically]
end
subgraph CLOUD [Cloud Provider]
DISK[EBS Disk / GCE PD /<br/>Azure Disk]
end
SC3 -->|referenced by| PVC3
PVC3 -->|triggers| PROV
PROV -->|creates| PV3
PROV -->|provisions| DISK
PV3 -->|bind| PVC3
PVC3 -->|referenced in| PODSPEC
Multi-container Patterns — Visual comparison
graph TB
subgraph INIT_PAT [Init Pattern]
I_IC[Init Container] -->|completes| I_APP[App Container]
I_IC <-->|volume| I_VOL[Volume]
I_APP <-->|volume| I_VOL
end
subgraph SIDECAR_PAT [Sidecar Pattern]
S_APP[App Container] <-->|volume| S_VOL[Volume]
S_SC[Sidecar Container] <-->|volume| S_VOL
EXT_GIT[Git Repo] -->|sync| S_SC
end
subgraph ADAPTER_PAT [Adapter Pattern]
AD_APP[App Container<br/>metrics format A] -->|localhost| AD_SC[Adapter Container<br/>transforms to format B]
AD_SC -->|format B| PROM[Prometheus]
end
subgraph AMB_PAT [Ambassador Pattern]
AM_APP[App Container<br/>→ localhost:9000] -->|localhost| AM_SC[Ambassador Container]
AM_SC -->|manages auth/TLS/routing| EXT_API[External API]
end
Search Terms
kubernetes · developers · volumes · multi-container · pods · containers · service · yaml · accounts · container · pattern · pod · storage · volume · commands · concept · init · provisioning · pvc · account · architecture · essential · kubectl · storageclass