
Votre application tourne dans le cluster, mais vous ne pouvez pas y accéder. Kubernetes isole les pods du réseau extérieur par défaut, c'est voulu. Pour y accéder, vous disposez de 3 commandes complémentaires : kubectl expose crée un Service permanent, kubectl port-forward ouvre un tunnel temporaire vers un pod ou un service, et kubectl proxy donne accès à l'API Kubernetes via un proxy local. Ce guide vous aide à choisir la bonne commande et à l'utiliser correctement.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Choisir entre
expose,port-forwardetproxyselon votre besoin - Créer un Service avec
kubectl exposeen choisissant le bon type (ClusterIP, NodePort, LoadBalancer) - Rediriger un port local vers un pod ou un service pour le dev/debug
- Accéder à l'API Kubernetes et aux dashboards internes via
kubectl proxy - Diagnostiquer les problèmes de connectivité et de routage
Quelle commande utiliser ?
Section intitulée « Quelle commande utiliser ? »Le critère de tri n'est pas la difficulté mais la durée de vie de l'accès. expose crée un objet qui survit à votre session et à vos redémarrages de pods, les deux autres commandes disparaissent dès que vous fermez le terminal. Lisez donc la colonne Durée en premier : elle vous dit tout de suite si vous êtes en train de modifier l'état du cluster ou simplement d'ouvrir une fenêtre depuis votre poste.
| Besoin | Commande | Durée | Ce que ça fait |
|---|---|---|---|
| Rendre une app accessible dans le cluster | kubectl expose --type=ClusterIP | Permanent | Crée un Service avec une IP interne stable |
| Rendre une app accessible hors du cluster | kubectl expose --type=NodePort ou LoadBalancer | Permanent | Crée un Service avec accès externe |
| Accéder à un pod/service depuis ma machine (dev, debug) | kubectl port-forward | Temporaire (durée de la commande) | Tunnel direct local → pod/service |
| Explorer l'API Kubernetes ou accéder à un dashboard | kubectl proxy | Temporaire (durée de la commande) | Proxy HTTP local vers l'API server |
kubectl expose : créer un Service
Section intitulée « kubectl expose : créer un Service »kubectl expose crée un objet Service qui devient le point d'entrée réseau permanent vers votre application. Le Service utilise les labels de la ressource ciblée pour trouver les pods à router.
Le premier argument est le type de ressource source, pas le type de Service : on expose un deployment, un replicaset, un pod ou même un Service existant. Kubernetes lit alors les labels de cette ressource pour construire le selector du nouveau Service. C'est ce mécanisme automatique qui explique la panne la plus fréquente, un Service sans endpoints : si vous exposez une ressource dont les labels ne figurent pas sur les pods réellement en cours d'exécution, le Service est créé mais ne route vers rien.
kubectl expose <type> <nom> --port=<port-service> --target-port=<port-conteneur> --type=<type-service>--port: le port exposé par le Service (celui que les clients utiliseront)--target-port: le port sur lequel le conteneur écoute (défini dans le pod)--type: le type de Service à créer
Les 3 types de Services
Section intitulée « Les 3 types de Services »Ces trois types forment une pile, pas trois options indépendantes : un NodePort est un ClusterIP auquel s'ajoute un port sur chaque nœud, et un LoadBalancer est un NodePort auquel s'ajoute un équilibreur externe. Vous verrez d'ailleurs dans les sorties ci-dessous qu'un Service NodePort conserve bien une CLUSTER-IP. Retenez la conséquence pratique : passer au type supérieur n'enlève jamais l'accès du type inférieur, cela ne fait qu'élargir l'exposition.
Le Service reçoit une IP interne accessible uniquement depuis l'intérieur du cluster. C'est le choix par défaut et le plus courant pour la communication entre microservices.
kubectl expose deploy api-gateway --port=80 --target-port=8080service/api-gateway exposedVérification :
kubectl get svc api-gatewayNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEapi-gateway ClusterIP 10.96.45.123 <none> 80/TCP 5sLe Service est accessible depuis n'importe quel pod du cluster via api-gateway.default.svc.cluster.local:80 ou simplement api-gateway:80 dans le même namespace.
Le Service ouvre un port fixe (30000-32767) sur chaque nœud du cluster. Tout trafic arrivant sur <IP-noeud>:<NodePort> est routé vers les pods.
kubectl expose deploy api-gateway --port=80 --target-port=8080 --type=NodePortNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEapi-gateway NodePort 10.96.45.123 <none> 80:31245/TCP 5sL'application est accessible sur http://<IP-de-nimporte-quel-noeud>:31245.
Le Service demande un load balancer externe au cloud provider (AWS ELB, GCP LB, Azure LB…). Il reçoit une IP publique ou un hostname DNS.
kubectl expose deploy api-gateway --port=80 --target-port=8080 --type=LoadBalancerNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEapi-gateway LoadBalancer 10.96.45.123 203.0.113.42 80:31245/TCP 30sChoisir les bons ports
Section intitulée « Choisir les bons ports »La confusion entre --port et --target-port est l'erreur la plus fréquente. Voici comment les distinguer :
Client → [Service:port] → [Pod:targetPort]| Flag | Ce qu'il définit | Exemple |
|---|---|---|
--port | Le port du Service (côté client) | 80, les autres pods appellent api-gateway:80 |
--target-port | Le port du conteneur (côté application) | 8080, votre app écoute sur 8080 |
Si --target-port est omis, il prend la même valeur que --port.
Exposer avec un nom personnalisé
Section intitulée « Exposer avec un nom personnalisé »Par défaut, le Service prend le nom de la ressource exposée, ce qui provoque un conflit dès que vous voulez deux Services sur le même Deployment, par exemple un ClusterIP interne et un NodePort de test. L'option --name lève ce blocage. Choisissez un nom explicite : il devient le nom DNS utilisé par les autres pods, et le renommer plus tard casse tous les appels qui le référencent.
kubectl expose deploy api-gateway --port=80 --target-port=8080 --name=api-publicVérifier que le Service route correctement
Section intitulée « Vérifier que le Service route correctement »Un Service peut exister, avoir une IP, répondre à kubectl get et pourtant ne router vers aucun pod. La vérification tient en trois étapes qui vont du symptôme à la cause : d'abord regarder s'il y a des endpoints, ensuite comparer selector et labels si la liste est vide, enfin confirmer par un appel réel depuis l'intérieur du cluster. Ne sautez pas la troisième : des endpoints présents prouvent que les pods sont sélectionnés, pas que l'application écoute sur le bon port.
-
Vérifiez que le Service existe et a des endpoints
Fenêtre de terminal kubectl get svc api-gatewaykubectl get endpointslices -l kubernetes.io/service-name=api-gatewayLa colonne
ENDPOINTSdoit contenir au moins une adresse IP de pod. Si elle est vide, le Service ne trouve aucun pod correspondant à son selector. La commande historiquekubectl get endpointsdonne la même information, mais l'APIEndpointsest dépréciée depuis Kubernetes 1.33 au profit des EndpointSlices : prenez l'habitude d'utiliser la nouvelle. -
Comparez les selectors du Service avec les labels des pods
Fenêtre de terminal # Selector du Servicekubectl get svc api-gateway -o jsonpath='{.spec.selector}'# Labels des podskubectl get pods --show-labelsLes labels des pods doivent correspondre exactement au selector du Service.
-
Testez la connectivité depuis un pod du cluster
Fenêtre de terminal kubectl run test-curl --rm -i --restart=Never --image=curlimages/curl:8.19.0 -- \curl -s -o /dev/null -w "%{http_code}\n" http://api-gateway:80La sortie doit afficher
200. Le pod jetable est supprimé automatiquement grâce à--rm.--restart=Neverfixe larestartPolicydu pod àNever: sans cette option, la valeur par défautAlwaysrelance le conteneur en boucle dès quecurla terminé, et la commande ne rend jamais la main.
kubectl port-forward : tunnel temporaire pour le dev
Section intitulée « kubectl port-forward : tunnel temporaire pour le dev »kubectl port-forward crée un tunnel direct entre votre machine locale et un pod ou un service dans le cluster. Le tunnel reste actif tant que la commande tourne, coupez-la et l'accès disparaît.
Quand l'utiliser
Section intitulée « Quand l'utiliser »Le point commun de ces quatre cas est qu'ils sont individuels et ponctuels : un seul développeur, une seule session, aucune trace laissée dans le cluster. Dès que le besoin devient collectif ou récurrent, port-forward cesse d'être le bon outil, car chaque utilisateur doit relancer sa commande et rien n'est documenté dans les manifests. Le quatrième cas mérite un avertissement : accéder à une base de données de production depuis un client graphique local reste un accès de production, avec les mêmes règles de traçabilité.
- Débugger une application qui n'est pas exposée à l'extérieur
- Accéder à un dashboard (Grafana, Prometheus, Kibana) sans créer de Service dédié
- Tester une API avant de la rendre accessible
- Accéder à une base de données depuis un outil local (DBeaver, pgAdmin…)
L'ordre des ports se lit local d'abord, distant ensuite, et l'inverser est l'erreur la plus fréquente : 8080:3000 ouvre le port 8080 sur votre machine vers le port 3000 du pod. Le tunnel passe par l'API server du cluster, ce qui a deux conséquences : vous n'avez besoin d'aucune route réseau vers les nœuds, mais chaque tunnel consomme une connexion sur l'API server, d'où l'intérêt de fermer ceux que vous n'utilisez plus.
kubectl port-forward <type>/<nom> <port-local>:<port-distant> [-n namespace]Recettes courantes
Section intitulée « Recettes courantes »Accéder à un pod
Section intitulée « Accéder à un pod »Cibler un pod nommément est le cas le plus direct, mais aussi le plus fragile : le nom contient un identifiant généré qui change à chaque recréation du pod.
kubectl port-forward pod/api-server-7d4b8c 8080:8080 -n prodForwarding from 127.0.0.1:8080 -> 8080Forwarding from [::1]:8080 -> 8080Les deux lignes correspondent aux écoutes IPv4 et IPv6 ; l'absence de la seconde sur certains systèmes est normale. Ouvrez ensuite http://localhost:8080 dans votre navigateur.
Accéder via un Service (recommandé)
Section intitulée « Accéder via un Service (recommandé) »Cibler un Service plutôt qu'un pod permet au port-forward de suivre automatiquement si le pod redémarre :
kubectl port-forward svc/grafana 3000:3000 -n monitoringRediriger plusieurs ports
Section intitulée « Rediriger plusieurs ports »Une seule commande peut ouvrir plusieurs redirections vers la même cible : il suffit d'enchaîner les couples local:distant. C'est utile quand une application expose son trafic applicatif et ses métriques sur deux ports distincts, ici 8080 et 9090. Un seul processus les tient tous : l'interrompre les ferme tous en même temps.
kubectl port-forward pod/mon-app-7d4b8c 8080:8080 9090:9090 -n prodChoisir l'adresse locale d'écoute
Section intitulée « Choisir l'adresse locale d'écoute »Par défaut, le tunnel n'écoute que sur 127.0.0.1. Pour le rendre accessible depuis d'autres machines de votre réseau :
kubectl port-forward --address 0.0.0.0 svc/grafana 3000:3000 -n monitoringLaisser le système choisir le port local
Section intitulée « Laisser le système choisir le port local »Si le port 8080 est déjà pris sur votre machine :
kubectl port-forward svc/api-gateway :8080 -n prodLe :8080 (sans port local) laisse le système attribuer un port libre. La commande affiche le port choisi.
Workflow typique : accéder à un dashboard Prometheus
Section intitulée « Workflow typique : accéder à un dashboard Prometheus »Cet enchaînement se transpose à n'importe quel outil interne : Grafana, Kibana, Argo CD, l'interface d'un opérateur. La seule étape qui demande de la réflexion est la première, car les distributions nomment leurs Services différemment ; le grep sert précisément à découvrir le nom réel plutôt qu'à le deviner. Notez aussi le port répété à l'identique, 9090:9090 : garder le même numéro des deux côtés évite les confusions quand plusieurs tunnels tournent en parallèle.
-
Identifiez le Service Prometheus
Fenêtre de terminal kubectl get svc -n monitoring | grep prometheusprometheus-server ClusterIP 10.96.12.45 <none> 9090/TCP 30d -
Ouvrez le tunnel
Fenêtre de terminal kubectl port-forward svc/prometheus-server 9090:9090 -n monitoring -
Accédez au dashboard
Ouvrez
http://localhost:9090dans votre navigateur. -
Coupez le tunnel quand vous avez terminé avec
Ctrl+C.
kubectl proxy : accéder à l'API Kubernetes
Section intitulée « kubectl proxy : accéder à l'API Kubernetes »kubectl proxy démarre un serveur proxy HTTP local qui authentifie automatiquement vos requêtes vers l'API server Kubernetes. Vous pouvez ensuite explorer l'API REST avec curl, un navigateur, ou n'importe quel outil HTTP.
Quand l'utiliser
Section intitulée « Quand l'utiliser »Ces trois usages ont un point commun : ils passent par l'API server plutôt que par le réseau des pods. C'est ce qui distingue proxy de port-forward, et cela impose une limite nette, seul le trafic HTTP est possible. Pour une base de données PostgreSQL ou un service gRPC en TCP brut, kubectl proxy ne convient pas.
- Explorer l'API Kubernetes (lister les ressources, vérifier les autorisations)
- Accéder aux dashboards exposés via l'API server (Kubernetes Dashboard)
- Développer un outil qui interagit avec l'API Kubernetes
Les deux options gouvernent uniquement le côté local du proxy. L'authentification vers le cluster, elle, est reprise telle quelle de votre kubeconfig : le proxy agit avec vos droits RBAC, ni plus ni moins. C'est la raison pour laquelle il ne faut jamais l'ouvrir au-delà de 127.0.0.1, quiconque atteint le port obtient l'intégralité de vos permissions sans avoir à présenter le moindre identifiant.
kubectl proxy [--port=<port>] [--address=<adresse>]Démarrer le proxy
Section intitulée « Démarrer le proxy »kubectl proxy --port=8001Starting to serve on 127.0.0.1:8001Le proxy reste actif tant que la commande tourne. Arrêtez-le avec Ctrl+C.
Explorer l'API
Section intitulée « Explorer l'API »Une fois le proxy démarré, l'API Kubernetes est accessible sans jeton ni certificat dans la requête, puisque le proxy les ajoute pour vous. Le passage par python3 -m json.tool sert uniquement à rendre la sortie lisible ; sur une liste de pods d'un namespace chargé, la réponse brute dépasse facilement plusieurs milliers de lignes. Pour un usage régulier, jq permet en plus de filtrer les champs qui vous intéressent.
# Lister les API disponiblescurl -s http://localhost:8001/api | python3 -m json.tool
# Lister les nœudscurl -s http://localhost:8001/api/v1/nodes | python3 -m json.tool
# Lister les pods d'un namespacecurl -s http://localhost:8001/api/v1/namespaces/prod/pods | python3 -m json.tool
# Obtenir un pod spécifiquecurl -s http://localhost:8001/api/v1/namespaces/prod/pods/api-server-7d4b8c | python3 -m json.toolAccéder à un Service via le proxy
Section intitulée « Accéder à un Service via le proxy »Le proxy expose aussi les Services de votre cluster via un chemin formaté. Deux détails de syntaxe piègent systématiquement. Le préfixe https: devant le nom du Service indique que le proxy doit contacter le backend en HTTPS, il ne s'agit pas du protocole de votre requête locale. Et la barre oblique finale de /proxy/ est obligatoire : sans elle, l'API server répond une redirection que la plupart des clients ne suivent pas correctement.
http://localhost:8001/api/v1/namespaces/<namespace>/services/<service>[:<port>]/proxy/# Accéder au dashboard Kubernetescurl http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/
# Accéder à Grafanacurl http://localhost:8001/api/v1/namespaces/monitoring/services/grafana:3000/proxy/proxy vs port-forward : quelle différence ?
Section intitulée « proxy vs port-forward : quelle différence ? »La ligne décisive est la dernière. kubectl proxy ne transporte que du HTTP parce qu'il traduit vos requêtes en appels d'API, alors que port-forward établit un tunnel TCP neutre au contenu. Concrètement, si vous devez brancher un client PostgreSQL, Redis ou gRPC, la question ne se pose pas, c'est port-forward. Le proxy garde l'avantage quand la cible est l'API elle-même ou une interface web servie à travers elle.
| Critère | kubectl proxy | kubectl port-forward |
|---|---|---|
| Ce qui est exposé | L'API Kubernetes complète | Un pod ou service spécifique |
| Protocole | HTTP uniquement | TCP (n'importe quel protocole) |
| Auth | Automatique (le proxy s'authentifie) | Automatique (kubectl s'authentifie) |
| Usage | Explorer l'API, accéder aux dashboards via l'API | Debug/dev, accéder à une app spécifique |
| URL d'accès | http://localhost:8001/api/v1/... | http://localhost:<port-local> |
| TCP brut (BD, gRPC…) | ❌ Non (HTTP only) | ✅ Oui |
Bonnes pratiques
Section intitulée « Bonnes pratiques »Choix du type de Service
Section intitulée « Choix du type de Service »La dernière ligne est celle qui compte en production réelle. Multiplier les Services LoadBalancer revient à multiplier les adresses IP publiques facturées par le cloud, une par service exposé. Un Ingress Controller placé devant des Services ClusterIP mutualise un seul point d'entrée pour toutes vos applications, avec en prime la terminaison TLS et le routage par nom d'hôte ou par chemin.
| Environnement | Type recommandé | Pourquoi |
|---|---|---|
| Communication entre microservices | ClusterIP | Pas besoin d'accès externe, routage interne |
| Cluster de dev/test, accès depuis le réseau local | NodePort | Simple, pas de dépendance cloud |
| Production, accès public | LoadBalancer | IP stable, health checks, intégration cloud |
| Production avec routing avancé (TLS, path-based) | ClusterIP + Ingress | Plus flexible qu'un LB par Service |
Port-forward : discipline de dev
Section intitulée « Port-forward : discipline de dev »Ces quatre règles visent le même écueil : un port-forward est une dette d'exploitation invisible. Rien dans le cluster n'indique qu'un accès existe, rien ne le documente, et il disparaît au premier redémarrage du poste. La deuxième règle est celle qu'on oublie le plus, un tunnel laissé ouvert des jours durant maintient une connexion sur l'API server et échoue silencieusement dès que le pod cible est recréé.
- Utilisez
svc/plutôt quepod/, le Service survit aux redémarrages de pods - Ne laissez pas tourner un port-forward oublié, il consomme une connexion API server
- Pour un accès régulier, créez un Service ou un Ingress plutôt que de relancer un port-forward chaque jour
- Documentez les commandes port-forward fréquentes dans le
READMEdu projet
Sécurité
Section intitulée « Sécurité »Le deuxième point est le plus sous-estimé. kubectl proxy n'accorde pas un accès à une application, il accorde un accès à l'API du cluster avec l'ensemble de vos droits RBAC. Si vous êtes cluster-admin, toute personne capable d'atteindre le port du proxy l'est aussi, sans authentification. Traitez ce port comme vous traiteriez votre fichier kubeconfig.
- Jamais
--address 0.0.0.0sur un réseau public (ni pour proxy, ni pour port-forward) kubectl proxy= accès complet au cluster avec vos droits. Traitez-le comme un accès admin- En production, préférez un Ingress Controller avec TLS plutôt qu'un NodePort ou proxy
Dépannage
Section intitulée « Dépannage »Une méthode avant le tableau : ces neuf symptômes se répartissent en deux familles qui ne se diagnostiquent pas de la même façon. Les erreurs de création (no resources found, already exists) sont explicites et se corrigent en relisant la commande. Les erreurs de routage (pas d'endpoints, 503, tunnel qui se coupe) sont muettes du côté de kubectl et demandent de remonter la chaîne : Service, puis EndpointSlice, puis état du pod, puis port réellement écouté par l'application.
| Symptôme | Cause probable | Solution |
|---|---|---|
error: no resources found (expose) | La ressource n'existe pas ou mauvais namespace | Vérifiez avec kubectl get <type> -n <ns> |
service already exists (expose) | Un Service du même nom existe déjà | Supprimez-le avec kubectl delete svc <nom> ou choisissez un autre nom (--name) |
| Service créé mais pas d'endpoints | Le selector du Service ne matche aucun pod | Comparez kubectl get svc <nom> -o jsonpath='{.spec.selector}' avec les labels des pods |
unable to listen on port (port-forward) | Le port local est déjà utilisé | Changez le port local : 9090:8080 ou utilisez :8080 pour un port aléatoire |
error forwarding port (port-forward) | Le pod n'est pas en état Running | Vérifiez kubectl get pod <nom> -n <ns>, attendez qu'il soit prêt |
| Port-forward se coupe tout seul | Le pod a redémarré ou a été supprimé | Ciblez le Service (svc/) plutôt que le pod. Relancez la commande |
address already in use (proxy) | Un autre processus utilise le port 8001 | Changez de port : kubectl proxy --port=8002 |
unauthorized (proxy) | Kubeconfig invalide ou expiré | Vérifiez avec kubectl cluster-info. Renouvelez vos credentials si nécessaire |
| Proxy : accès au Service retourne 503 | Le Service n'a pas d'endpoints ou le pod n'est pas prêt | Vérifiez kubectl get endpoints <svc> -n <ns> |
À retenir
Section intitulée « À retenir »kubectl exposecrée un Service permanent, choisissez le bon type : ClusterIP (interne), NodePort (dev/test), LoadBalancer (prod cloud).kubectl port-forwardcrée un tunnel temporaire local → pod/service, parfait pour le dev et le debug, mais pas pour la production.kubectl proxyexpose l'API Kubernetes en HTTP local, puissant pour l'exploration, mais dangereux si exposé sur le réseau.--port= port du Service (côté client),--target-port= port du conteneur (côté application).- Ciblez un Service (
svc/) plutôt qu'un pod pour un port-forward résilient aux redémarrages. - En production, préférez un Ingress Controller avec TLS plutôt que des NodePort ou des proxy.
- Pour un accès régulier, créez un Service ou un Ingress, ne compensez pas avec un port-forward quotidien.