Varnish Cache, compilé depuis les sources et empaqueté dans une image FROM scratch. Son cas est le plus atypique du parc : c'est la seule image durcie qui embarque un shell et un compilateur, et ce n'est pas une négligence.
Rôle
Varnish est le cache HTTP qui accélère les réponses du site. Il est placé derrière le pare-feu applicatif et devant le pod applicatif : le trafic est donc inspecté avant d'être mis en cache. Cet article ne traite que de l'image ; son service — VCL, backends, purge, montée en charge — a le sien.
Image
| Propriété | Valeur |
|---|---|
| Image | jbsky/varnish-hardened |
| Base | FROM scratch |
| UID | 6081:65534 |
| Ports | 8080 (HTTP), 8443 |
| Healthcheck | requête HTTP sur le endpoint de santé |
| PID 1 | tini-static |
Pourquoi un cache HTTP embarque un compilateur C
Varnish ne lit pas son fichier de configuration : il le compile. Le VCL est traduit en C, puis en objet partagé, puis chargé à chaud dans le processus. Ce n'est pas un détail d'implémentation qu'on pourrait contourner, c'est le fonctionnement normal du produit : tout rechargement de configuration passe par une compilation.
Dans une image ordinaire, un compilateur est là ou s'installe en une ligne. Dans
une image FROM scratch, il n'y a rien. Le choix a donc été d'embarquer TCC
(Tiny C Compiler), environ 200 Ko, compilé depuis les sources, suffisant pour les
VCL que Varnish génère.
Ce que ce choix coûte vraiment
Varnish est la seule image du parc à embarquer un shell : busybox, avec sh et
rm qui pointent dessus. Elle embarque aussi TCC, aliasé en cc et gcc, et
338 fichiers d'en-têtes.
Rien de tout cela n'est décoratif : un compilateur C a besoin d'un shell pour être invoqué, d'en-têtes pour compiler, et de fichiers de démarrage qui ne sont pas eux-mêmes des binaires. C'est le prix d'un produit qui compile sa configuration.
C'est aussi ce qui explique une exception dans le parc : varnish est l'une des deux seules images à ne porter aucun magasin de certificats, parce qu'elle ne va rien chercher en HTTPS depuis le conteneur.
Le healthcheck est HTTP, pas TCP
Le binaire d'entrée écrit en Go expose deux modes : une vérification de santé, et un mode d'export d'outils. Le premier fait une requête HTTP sur le endpoint de santé plutôt qu'une simple ouverture de socket.
La différence n'est pas cosmétique. Un connect TCP réussit dès que le démon écoute, c'est-à-dire avant même que le VCL soit chargé. Une requête HTTP qui répond prouve que la configuration est compilée et que le cache traite réellement des requêtes. Sur un produit qui compile sa configuration au démarrage, c'est exactement la fenêtre où un healthcheck naïf ment.
Ce que le pod fait vraiment de cette image
Le pod de production lance plusieurs containers depuis cette seule image, avec des commandes différentes : le cache lui-même, et le logger d'accès qui lit le segment de mémoire partagée du démon. C'est ce qui justifie qu'elle embarque des points d'entrée au-delà du démon principal.
En revanche — et c'est le contresens à ne pas commettre — les sidecars qui surveillent le ConfigMap et rechargent le VCL à chaud ne tournent pas sur cette image. Ils utilisent une busybox séparée, précisément parce qu'ils ont besoin d'un shell pour faire leur travail. Le shell embarqué dans l'image durcie ne leur sert donc à rien : il est là pour le compilateur, et pour lui seul.
La distinction a son importance quand on audite ce qu'une image durcie contient. « Il y a un shell dedans » n'est pas une conclusion ; la question est de savoir quel processus l'invoque, et la réponse peut très bien être « aucun de ceux que je croyais ».
Lire ce qui tourne, pas ce que le chart propose
Deux vérifications valent d'être faites sur le cluster plutôt que dans le dépôt, parce que les deux sources divergent silencieusement.
Le tag déployé ne vit pas dans le chart de base mais dans les valeurs de la surcouche d'environnement : le chart peut donc proposer un tag que rien ne déploie.
Et un StatefulSet n'est pas re-rendu tant que rien ne le pousse. Constaté sur ce cluster : le pod portait encore un initContainer retiré du chart depuis, épinglé une version majeure derrière le reste du pod. Le dépôt était juste, le cluster aussi — ils décrivaient simplement deux moments différents.
Liens
- Code source : Dépôt varnish-hardened
- Image Docker : Docker Hub