Applications modernes sur OpenShift, partie 2 : constructions chaînées

Bonjour à tous ! Voici le deuxième post de notre série où nous montrons comment déployer des applications web modernes sur Red Hat OpenShift.

Applications modernes sur OpenShift, partie 2 : constructions chaînées

Dans le post précédent, nous avons brièvement abordé les capacités du nouveau builder-image S2I (source-to-image), conçu pour construire et déployer des applications web modernes sur la plateforme OpenShift. À l'époque, nous nous intéressions à la rapidité du déploiement d'une application, et aujourd'hui nous verrons comment utiliser l'image S2I en tant que builder-image « propre » et la combiner avec des builds associés OpenShift.

Builder-image propre

Comme mentionné dans la première partie, la plupart des applications web modernes ont ce qu'on appelle une étape de construction, où des opérations telles que la transpilation du code, la concaténation de plusieurs fichiers et la minification sont généralement effectuées. Les fichiers résultants de ces opérations – à savoir HTML statique, JavaScript et CSS – sont placés dans le dossier output. L'emplacement de ce dossier dépend généralement des outils de construction utilisés, et pour React, ce sera le dossier ./build (nous y reviendrons plus en détail ci-dessous).

Source-to-Image (S2I)

Dans ce post, nous n'aborderons pas le sujet de « ce qu'est S2I et comment l'utiliser » (vous pouvez lire plus à ce sujet ici), mais il est important d'avoir une compréhension claire des deux étapes de ce processus pour savoir ce que fait l'image Web App Builder.

Phase d'assemblage

La phase d'assemblage ressemble beaucoup à ce qui se passe lorsque vous lancez un docker build et que vous obtenez une nouvelle image Docker en résultat. Cette étape se produit donc lors du démarrage d'un build sur la plateforme OpenShift.

Dans le cas de l'image Web App Builder, l'installation des dépendances de votre application et le démarrage du build sont gérés par le script d'assemblage. Par défaut, l'image builder utilise la commande npm run build, mais elle peut être redéfinie via la variable d'environnement NPM_BUILD.

Comme nous l'avons mentionné précédemment, l'emplacement de l'application finale déjà assemblée dépend des outils utilisés. Par exemple, dans le cas de React, ce sera le dossier ./build, et pour les applications Angular, ce sera le dossier project_name/dist. Et, comme déjà montré dans le post précédent, l'emplacement du répertoire de sortie, qui est par défaut défini comme build, peut être redéfini via la variable d'environnement OUTPUT_DIR. Puisque l'emplacement du dossier de sortie varie d'un framework à l'autre, vous copiez simplement la sortie générée dans le dossier standard de l'image, à savoir dans /opt/apt-root/output. Cela est important pour comprendre la suite de cet article, mais pour l'instant, examinons rapidement la prochaine étape : la phase d'exécution (run phase).

Phase d'exécution (run phase)

Cette étape se produit lorsqu'un nouvel image, créée lors de l'étape d'assemblage, est appelée avec docker run. Elle se produit également lors du déploiement sur la plateforme OpenShift. Par défaut script d'exécution utilise module de service pour servir le contenu statique situé dans le répertoire de sortie standard mentionné ci-dessus.

Cette méthode est bonne pour un déploiement rapide d'applications, mais en réalité, il n'est pas recommandé de servir le contenu statique de cette manière. Étant donné que nous ne servons en réalité que du contenu statique, Node.js installé dans notre image n'est pas nécessaire – un serveur web suffit.

En d'autres termes, à la compilation, nous avons besoin d'une chose, en exécution, d'une autre. Dans cette situation, les constructions liées (chained builds) seront utiles.

Constructions liées (chained builds)

Voici ce que dit la documentation OpenShift à propos de chained builds :

« Deux constructions peuvent être liées l'une à l'autre, l'une générant une entité compilée et l'autre plaçant cette entité dans une image distincte, qui est utilisée pour exécuter cette entité.»

En d'autres termes, nous pouvons utiliser l'image Web App Builder pour exécuter notre construction, puis utiliser l'image du serveur web, comme NGINX, pour servir notre contenu.

Ainsi, nous pouvons appliquer l'image Web App Builder comme un « constructeur » « propre » tout en ayant une petite image d'exécution.

Passons maintenant à un exemple concret.

Pour cet exercice, nous utiliserons une application React simple, créée à l'aide de l'outil de ligne de commande create-react-app.

Pour tout rassembler, nous allons utiliser un fichier modèle OpenShift.

Examinons ce fichier plus en détail, et commençons par la section des paramètres.

paramètres :
  - nom : SOURCE_REPOSITORY_URL
    description : L'URL source de l'application
    displayName : URL source
    required : true
  - nom : SOURCE_REPOSITORY_REF
    description : Le nom de la branche pour l'application
    displayName : Branche source
    value : master
    required : true
  - nom : SOURCE_REPOSITORY_DIR
    description : L'emplacement au sein du dépôt source de l'application
    displayName : Répertoire source
    value : .
    required : true
  - nom : OUTPUT_DIR
    description : L'emplacement des fichiers statiques compilés de votre générateur d'applications web
    displayName : Répertoire de sortie
    value : build
    required : false

Tout cela est assez clair, mais il faut prêter attention au paramètre OUTPUT_DIR. Pour l'application React de notre exemple, il n'y a pas de souci, car React utilise par défaut la valeur de sortie par défaut, tandis que pour Angular ou d'autres, ce paramètre devra être ajusté de manière adéquate.

Jetons maintenant un œil à la section des ImageStreams.

- apiVersion : v1
  kind : ImageStream
  metadata :
    name : react-web-app-builder  // 1 
  spec : {}
- apiVersion : v1
  kind : ImageStream
  metadata :
    name : react-web-app-runtime  // 2 
  spec : {}
- apiVersion : v1
  kind : ImageStream
  metadata :
    name : web-app-builder-runtime // 3
  spec :
    tags :
    - name : latest
      from :
        kind : DockerImage
        name : nodeshift/ubi8-s2i-web-app:10.x
- apiVersion : v1
  kind : ImageStream
  metadata :
    name : nginx-image-runtime // 4
  spec :
    tags :
    - name : latest
      from :
        kind : DockerImage
        name : 'centos/nginx-112-centos7:latest'

Regardez les troisième et quatrième images. Elles sont toutes deux définies comme des images Docker, et il est clair de voir d'où elles proviennent.

La troisième image est web-app-builder, et elle provient de nodeshift/ubi8-s2i-web-app avec le tag 10.x sur Docker hub.

La quatrième est l'image NGINX (version 1.12) avec le tag latest sur Docker hub.

Jetons maintenant un œil aux deux premières images. Elles sont toutes deux vides au départ et ne sont créées qu'à l'étape de construction (build phase). La première image, react-web-app-builder, sera le résultat de l'étape d'assemblage, qui combinera l'image web-app-builder-runtime et notre code source. C'est pourquoi nous avons inscrit « -builder » dans le nom de cette image.

La deuxième image, react-web-app-runtime, sera le résultat de la combinaison de nginx-image-runtime et de certains fichiers de l'image react-web-app-builder. Cette image sera également utilisée lors du déploiement et contiendra uniquement le serveur web, ainsi que le HTML, le JavaScript et le CSS statiques de notre application.

C'est confus ? Regardons maintenant les configurations de construction et cela deviendra un peu plus clair.

Dans notre modèle, il y a deux configurations de construction. Voici la première d'entre elles, qui est assez standard :

  apiVersion: v1
  kind: BuildConfig
  metadata:
    name: react-web-app-builder
  spec:
    output:
      to:
        kind: ImageStreamTag
        name: react-web-app-builder:latest 
    source:   
      git:
        uri: ${SOURCE_REPOSITORY_URL}
        ref: ${SOURCE_REPOSITORY_REF}
      contextDir: ${SOURCE_REPOSITORY_DIR}
      type: Git
    strategy:
      sourceStrategy:
        env:
          - name: OUTPUT_DIR 
            value: ${OUTPUT_DIR}
        from:
          kind: ImageStreamTag
          name: web-app-builder-runtime:latest 
        incremental: true 
      type: Source
    triggers: 
    - github:
        secret: ${GITHUB_WEBHOOK_SECRET}
      type: GitHub
    - type: ConfigChange
    - imageChange: {}
      type: ImageChange

Comme nous le voyons, la ligne avec l'étiquette 1 indique que le résultat de cette construction sera placé dans l'image react-web-app-builder que nous avons vue précédemment dans la section ImageStream.

La ligne avec l'étiquette 2 indique d'où prendre le code. Dans notre cas, il s'agit d'un dépôt git, et l'URI, la référence et le répertoire contextuel sont définis par les paramètres que nous avons déjà vus ci-dessus.

La ligne avec l'étiquette 3 – nous l'avons déjà vue dans la section des paramètres. Elle ajoute la variable d'environnement OUTPUT_DIR, qui dans notre exemple est égale à build.
La ligne avec l'étiquette 4 indique d'utiliser l'image web-app-builder-runtime, que nous avons déjà vue dans la section ImageStream.

La ligne avec l'étiquette 5 indique que nous souhaitons utiliser une construction incrémentielle, si l'image S2I le prend en charge, et l'image Web App Builder le prend en charge. Lors du premier lancement, après la fin de l'assemblage, l'image conservera le dossier node_modules dans un fichier archive. Ensuite, lors des exécutions suivantes, l'image se contentera de décompresser ce dossier pour réduire la durée de construction.

Enfin, la ligne avec l'étiquette 6 – ce ne sont que quelques déclencheurs pour que la construction se lance automatiquement, sans intervention manuelle, lorsque quelque chose change.

En général, c'est une configuration de construction assez standard.

Jetons un œil à la deuxième configuration de construction. Elle est très similaire à la première, mais il y a une différence importante.

apiVersion: v1
  kind: BuildConfig
  metadata:
    name: react-web-app-runtime
  spec:
    output:
      to:
        kind: ImageStreamTag
        name: react-web-app-runtime:latest 
    source: 
      type: Image
      images:                              
        - from:
            kind: ImageStreamTag
            name: react-web-app-builder:latest 
          paths:
            - sourcePath: /opt/app-root/output/. 
              destinationDir: . 
             
    strategy: 
      sourceStrategy:
        from:
          kind: ImageStreamTag
          name: nginx-image-runtime:latest
        incremental: true
      type: Source
    triggers:
    - github:
        secret: ${GITHUB_WEBHOOK_SECRET}
      type: GitHub
    - type: ConfigChange
    - type: ImageChange
      imageChange: {}
    - type: ImageChange
      imageChange:
        from:
          kind: ImageStreamTag
          name: react-web-app-builder:latest

Donc, la deuxième configuration de construction – react-web-app-runtime, commence de manière assez standard.

Il n'y a rien de nouveau dans la ligne marquée 1 — elle indique simplement que le résultat de la construction est placé dans l'image react-web-app-runtime.

La ligne marquée 2, comme dans la configuration précédente, indique d'où prendre le code source. Mais notez que nous disons ici qu'il provient de l'image. En fait, de l'image que nous venons de créer – react-web-app-builder (indiquée dans la ligne marquée 3). Les fichiers que nous voulons utiliser se trouvent à l'intérieur de l'image et leur emplacement y est défini dans la ligne marquée 4, qui est /opt/app-root/output/. Si vous vous souvenez, c'est précisément là que sont stockés les fichiers générés par les résultats de la construction de notre application.

Le dossier de destination, défini dans la ligne marquée 5, est simplement le répertoire courant (rappelez-vous que tout cela fonctionne à l'intérieur d'une sorte de chose magique appelée OpenShift, et non sur votre ordinateur local).

La section strategy – ligne marquée 6 – ressemble également à la première configuration de construction. Cette fois, nous allons utiliser nginx-image-runtime, que nous avons déjà vu dans la section ImageStream.

Enfin, la ligne marquée 7 – est la section des déclencheurs qui active cette construction chaque fois que l'image react-web-app-builder change.

Pour le reste, ce modèle contient une configuration de déploiement tout à fait standard, ainsi que des éléments liés aux services et aux routes, mais nous ne nous attarderons pas là-dessus. Notez que l'image qui sera déployée est l'image react-web-app-runtime.

Déploiement de l'application

Donc, après avoir examiné le modèle, voyons comment l'utiliser pour déployer l'application.

Nous pouvons utiliser l'outil client OpenShift appelé oc pour déployer notre modèle :

$ find . | grep openshiftio | grep application | xargs -n 1 oc apply -f

$ oc new-app --template react-web-app -p SOURCE_REPOSITORY_URL=https://github.com/lholmquist/react-web-app

La première commande à l'écran ci-dessus est un moyen délibérément technique de trouver le modèle /openshiftio/application.yaml.

La deuxième commande crée simplement une nouvelle application basée sur ce modèle.

Après que ces commandes aient fonctionné, nous verrons que nous avons deux constructions :

Applications modernes sur OpenShift, partie 2 : constructions chaînées

Et en retournant à l'écran Overview, nous verrons le pod démarré :

Applications modernes sur OpenShift, partie 2 : constructions chaînées

Un clic sur le lien — et nous serons redirigés vers notre application, qui est une page d'application React App par défaut :

Applications modernes sur OpenShift, partie 2 : constructions chaînées

Annexe 1

Pour les amateurs d'Angular, nous avons aussi exemple d'application.

Le modèle ici est le même, à l'exception de la variable OUTPUT_DIR.

Annexe 2

Dans cet article, nous avons utilisé NGINX comme serveur web, mais il est assez facile de le remplacer par Apache, il suffit de modifier le fichier modèle image NGINX sur image Apache.

Conclusion

Dans la première partie de cette série, nous avons montré comment déployer rapidement des applications web modernes sur la plateforme OpenShift. Aujourd'hui, nous avons examiné ce que fait l'image Web App et comment elle peut être associée à un serveur web pur comme NGINX grâce à des builds liés (chained build) pour organiser une construction d'application plus adaptée aux conditions de production. Dans le prochain article final de cette série, nous montrerons comment exécuter un serveur de développement sur OpenShift pour votre application et synchroniser les fichiers locaux et distants.

Contenu de cette série d'articles

  • Partie 1 : comment déployer des applications web modernes en quelques étapes seulement;
  • Partie 2 : comment appliquer la nouvelle image S2I avec l'image de serveur HTTP déjà existante, comme NGINX, en utilisant des builds liés d'OpenShift, pour organiser un déploiement en production ;
  • Partie 3 : comment exécuter un serveur de développement sur la plateforme OpenShift pour votre application et le synchroniser avec le système de fichiers local.

Ressources supplémentaires

Source : habr.com

Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS 🔥 Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS | ProHoster