Je construis un serveur, écrit en C++ et je souhaite le déployer en utilisant Docker avec docker-compose . Quelle est la "bonne façon" de le faire? Dois-je appeler make
à partir de Dockerfile ou créer manuellement, télécharger sur un serveur puis COPY
binaires à partir de Dockerfile?
J'ai eu des difficultés à automatiser notre build avec docker-compose
, et j'ai fini par utiliser docker build
pour tout:
Trois couches pour la construction
Exécuter → développer → construire
Ensuite, je copie les sorties de build dans l'image "deploy":
Exécuter → déployer
Quatre couches pour jouer avec:
FROM <projname>:run
FROM <projname>:develop
FROM <projname>:run
RUN
ou ENTRYPOINT
utilisé pour lancer l'applicationLa structure des dossiers ressemble à ceci:
.
├── run
│ └── Dockerfile
├── develop
│ └── Dockerfile
├── build
│ ├── Dockerfile
│ └── removeOldImages.sh
└── deploy
├── Dockerfile
└── pushImage.sh
Configurer le serveur de build signifie exécuter:
docker build -f run -t <projName>:run
docker build -f develop -t <projName>:develop
Chaque fois que nous faisons une construction, cela se produit:
# Execute the build
docker build -f build -t <projName>:build
# Install build outputs
docker build -f deploy -t <projName>:version
# If successful, Push deploy image to dockerhub
docker tag <projName>:<version> <projName>:latest
docker Push <projName>:<version>
docker Push <projName>:latest
Je renvoie les gens aux Dockerfiles en tant que documentation sur la façon de construire/exécuter/installer le projet.
Si une génération échoue et que la sortie est insuffisante pour une enquête, je peux exécuter /bin/bash
dans <projname>:build
et fouiller pour voir ce qui ne va pas.
J'ai mis en place n référentiel GitHub autour de cette idée. Cela fonctionne bien pour C++, mais vous pouvez probablement l'utiliser pour n'importe quoi.
Je n'ai pas exploré la fonctionnalité, mais @TaylorEdmiston a souligné que mon modèle ici est assez similaire à constructions multi-étapes , que je ne connaissais pas lorsque j'ai trouvé cela. Cela ressemble à une manière plus élégante (et mieux documentée) de réaliser la même chose.
Ma recommandation serait de développer, construire et tester complètement le conteneur lui-même. Cela garantit la philosophie Docker selon laquelle l'environnement du développeur est le même que l'environnement de production, voir La station de travail de développeur moderne sur MacOS avec Docker.
Surtout, dans le cas d'applications C++ où il existe généralement des dépendances avec des bibliothèques/fichiers objets partagés.
Je ne pense pas qu'il existe encore de processus de développement standardisé pour développer, tester et déployer des applications C++ sur Docker.
Pour répondre à votre question, la façon dont nous le faisons actuellement est de traiter le conteneur comme votre environnement de développement et d'appliquer un ensemble de pratiques à l'équipe comme:
docker diff
les changements sont comme prévu .Pour toute personne visitant cette question après 2017, veuillez consulter la réponse par fuglede à propos de l'utilisation constructions Docker à plusieurs étapes , c'est vraiment une meilleure solution que ma réponse (ci-dessous) de 2015, bien avant qu'elle ne soit disponible.
La façon dont je le ferais est d'exécuter votre build en dehors de votre conteneur et de copier uniquement la sortie de la build (votre binaire et toutes les bibliothèques nécessaires) dans votre conteneur. Vous pouvez ensuite télécharger votre conteneur dans un registre de conteneurs (par exemple, utiliser un hébergé ou exécuter le vôtre), puis extraire de ce registre sur vos machines de production. Ainsi, le flux pourrait ressembler à ceci:
Comme il est important que vous testiez avant le déploiement en production, vous souhaitez tester exactement la même chose que vous déploierez en production, de sorte que vous ne voulez pas extraire ou modifier l'image Docker de quelque manière que ce soit après l'avoir créée.
Je n'exécuterais pas la construction à l'intérieur du conteneur que vous prévoyez de déployer dans prod, car alors votre conteneur aura toutes sortes d'artefacts supplémentaires (comme une construction temporaire sorties, outillage, etc.) dont vous n'avez pas besoin en production et développez inutilement votre image de conteneur avec des choses que vous n'utiliserez pas pour votre déploiement.
Alors que les solutions présentées dans les autres réponses - et en particulier la suggestion de Misha Brukman dans les commentaires de cette réponse sur l'utilisation d'un Dockerfile pour le développement et une pour la production - seraient considérées comme idiomatiques à l'époque la question a été écrite, il convient de noter que les problèmes qu'ils essaient de résoudre - et en particulier la question du nettoyage de l'environnement de construction pour réduire la taille de l'image tout en étant en mesure d'utiliser le même environnement de conteneur dans le développement et la production - ont été effectivement résolus par builds multi-stage, qui ont été introduits dans Docker 17.05.
L'idée ici serait de diviser le Dockerfile en deux parties, une qui est basée sur votre environnement de développement préféré, comme une image de base Debian à part entière, qui concerne la création des binaires que vous souhaitez déployer à la fin de la jour, et un autre qui exécute simplement les binaires construits dans un environnement minimal, comme Alpine.
De cette façon, vous évitez les éventuelles divergences entre les environnements de développement et de production, comme le mentionne blueskin dans l'un des commentaires, tout en vous assurant que votre image de production n'est pas polluée par les outils de développement.
La documentation fournit l'exemple suivant d'une construction en plusieurs étapes d'une application Go, que vous adopteriez ensuite dans un environnement de développement C++ (avec un problème étant qu'Alpine utilise musl vous devez donc être prudent lorsque liaison dans votre environnement de développement).
FROM golang:1.7.3
WORKDIR /go/src/github.com/alexellis/href-counter/
RUN go get -d -v golang.org/x/net/html
COPY app.go .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
FROM Alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=0 /go/src/github.com/alexellis/href-counter/app .
CMD ["./app"]