[Partie 1] Testez et déployez automatiquement les services WEB créés avec Rails + Nuxt + MySQL + Docker avec ECS / ECR / CircleCI pour terraformer

En écrivant cet article

[AWS? Docker?] Résumez les connaissances nécessaires dans votre portefeuille d'une manière simple à comprendre [terraform? CircleCI?]

CircleCI? ?? ?? Docker ??? Les gens devraient regarder cela en premier. ↑

Étudier pour étudier ne veut pas dire grand-chose ... Alors bougez d'abord vos mains! Alors cette fois, j'écrirai un article dans un format pratique. J'espère que ceux qui le liront pourront rapidement créer un environnement de développement et se concentrer rapidement sur le développement.

Je l'ai reproduit dans mon environnement environ 3 fois afin de ne pas souffrir au maximum d'erreurs.

Je pense que ce sera probablement une trilogie ... Je suis désolé, c'est long.

Premièrement: cet article 2e: [[Part 2] Déployez automatiquement le service WEB créé avec Rails + Nuxt + MySQL + Docker avec ECS / ECR / CircleCI et faites-le terraform](https://qiita.com/Shogo1222/items/ dcbc1e50f6fc83f48b44) Troisièmement: [Partie 2] Déployez automatiquement le service WEB créé avec Rails + Nuxt + MySQL + Docker avec ECS / ECR / CircleCI et faites-le terraformer

Objectifs de cet article

C'est long, mais faisons de notre mieux!

environnement d'utilisation

MacOS Catalina 10.15.5 Rails 6.0.3.2 @vue/cli 4.4.4 @nuxt/cli v2.14.4 Vuetify Docker(forMac) version 19.03.8 docker-compose version 1.25.5

supposition

--Docker installé
Installer Docker sur Mac (mise à jour: 2019/7/13) --CircleCI compte créé
Je viens de démarrer CircleCI, donc je l'ai résumé d'une manière facile à comprendre --Création d'un compte git
[6.1 Préparation et configuration du compte GitHub](https://git-scm.com/book/ja/v2/GitHub-%E3%82%A2%E3%82%AB%E3%82%A6%E3% 83% B3% E3% 83% 88% E3% 81% AE% E6% BA% 96% E5% 82% 99% E3% 81% A8% E8% A8% AD% E5% AE% 9A)

Produit fini

J'ai donné le produit fini à git. qiita-sample-app

Construction de développement environnemental avec Docker

Réglage initial

Ce but

app //N'importe quel nom va bien
├─docker-compose.yml 
├─front
|   ├─Dockerfile
└─back 
    ├─Dockerfile
    ├─Gemfile
    └─Gemfile.lock

Créer un répertoire de travail

mkdir app
cd app //Aller à l'App
mkdir front //création avant
mkdir back //création de retour
touch ./back/Dockerfile
touch ./back/Gemfile
touch ./back/Gemfile.lock
mkdir ./back/environments
touch ./back/environments/db.env

touch ./front/Dockerfile

touch docker-compose.yml

Description de Dockerfile

Modifier Dockerfile dans / arrière

back/Dockerfile


#Spécifier une image
FROM ruby:2.6.3-alpine3.10

#Télécharger les packages requis
ENV RUNTIME_PACKAGES="linux-headers libxml2-dev make gcc libc-dev nodejs tzdata mysql-dev mysql-client yarn" \
    DEV_PACKAGES="build-base curl-dev" \
    HOME="/app" \
    LANG=C.UTF-8 \
    TZ=Asia/Tokyo

#Déplacer vers le répertoire de travail
WORKDIR ${HOME}

#Copiez les fichiers nécessaires de l'hôte (fichiers sur votre ordinateur) vers Docker
ADD Gemfile ${HOME}/Gemfile
ADD Gemfile.lock ${HOME}/Gemfile.lock

RUN apk update && \
    apk upgrade && \
    apk add --update --no-cache ${RUNTIME_PACKAGES} && \
    apk add --update --virtual build-dependencies --no-cache ${DEV_PACKAGES} && \
    bundle install -j4 && \
    apk del build-dependencies && \
    rm -rf /usr/local/bundle/cache/* \
    /usr/local/share/.cache/* \
    /var/cache/* \
    /tmp/* \
    /usr/lib/mysqld* \
    /usr/bin/mysql*

#Copiez les fichiers nécessaires de l'hôte (fichiers sur votre ordinateur) vers Docker
ADD . ${HOME}

#Ouvrir le port 3000
EXPOSE 3000

#Exécuter la commande
CMD ["bundle", "exec", "rails", "s", "puma", "-b", "0.0.0.0", "-p", "3000", "-e", "development"]

Modifier Dockerfile dans / devant

front/Dockerfile


FROM node:12.5.0-alpine

ENV HOME="/app" \
    LANG=C.UTF-8 \
    TZ=Asia/Tokyo

ENV HOST 0.0.0.0

WORKDIR ${HOME}

RUN apk update && \
    apk upgrade && \
    npm install -g n && \
    yarn install &&\
    rm -rf /var/cache/apk/*

#Je l'enlèverai plus tard(Lors de l'utilisation d'ECS)

#RUN yarn run build
#EXPOSE 3000
#CMD ["yarn", "dev"]

Description de Gemfile

back/Gemfile


source 'https://rubygems.org'
gem 'rails', '~>6'

Description de docker-compose.yml

yml:./docker-compose.yml


version: "3"

services:
  db:
    image: mysql:5.7
    env_file:
      - ./back/environments/db.env
    restart: always
    volumes:
      - db-data:/var/lib/mysql:cached

  back:
    build: back/
    # rm -f tmp/pids/server.Utile lorsque vous ne parvenez pas à effacer le serveur de rails avec pid
    command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'" 
    env_file:
      - ./back/environments/db.env
    volumes:
      - ./back:/app:cached
    depends_on:
      - db
    #Port de l'ordinateur hôte: port dans Docker
    ports:
      - 3000:3000

  front:
    build: front/
    command: yarn run dev
    volumes:
      - ./front:/app:cached
    ports:
      #Port de l'ordinateur hôte: port dans Docker
      - 8080:3000
    depends_on:
      - back
volumes:
  public-data:
  tmp-data:
  log-data:
  db-data:

Connaissance des haricots

Le réseau dans Docker est différent du réseau sur la machine hôte. Par exemple, le processus rails lancé par Docker est démarré à localhost (127.0.0.1): 3000 dans l'environnement virtuel (conteneur). Il est différent de localhost sur la machine hôte.

Cependant, il peut être résolu par le mappage de port dans docker-compose.yml.

Si vous spécifiez le port hôte 3000 et le port conteneur 3000 et que vous vous connectez à 0.0.0.0, vous pouvez accéder avec localhost comme si vous l'aviez démarré sur la machine hôte. C'est ce qu'on appelle la redirection de port.

Vous pouvez accéder au processus intégré dans l'environnement virtuel normalement en spécifiant l'adresse de liaison et en effectuant la redirection de port.

référence: La signification de l'option -b des rails s -b 0.0.0.0

Alors, que signifie 8080: 3000? Ce port mappe le port conteneur 3000 au port hôte 8080 (≒ redirection de port). En d'autres termes, le processus nuxt construit à l'intérieur du conteneur Docker utilise le port 3000, mais lorsque vous naviguez sur la machine hôte, rendez-le visible sur 8080. (Si Rails vaut également 3000, il sera dupliqué dans la machine hôte, donc une erreur se produira)


Définissons db.env

./back/db.env


MYSQL_ROOT_PASSWORD=rootpassword
MYSQL_USER=username
MYSQL_PASSWORD=userpassword

Construisons avec Docker Compose

./


docker-compose build

Cela prendra du temps. Vous n'avez pas besoin de construire plusieurs fois, lancez-le simplement lorsque vous changez Gemfile ou Dockerfile! (Je l'ai fait plusieurs fois au début et j'ai perdu du temps.)

C'est la commande docker-compose qui est sortie pour la première fois, mais à partir de maintenant j'utiliserai beaucoup cette commande.

hello, Nuxt

Ce but

Créer une application nuxt sous front Bonjour tout le monde avec Nuxt!

La structure finale du répertoire ressemble à ceci.

...Abréviation
front
├─Dockerfile
...Abréviation
├─components //Où placer les composants de vue
├─layouts //Où l'index appelle par défaut
├─pages //Ajouter ici lors de l'ajout d'une page
├─plugins //Où mettre le fichier de configuration du plugin à ajouter avec du fil, etc.
├─nuxt.config.js //nuxt lui-même fichier de configuration
├─package.json //Où définir la dépendance de package de yarn / npm
...Abréviation

Créons une application nuxt

./


docker-compose build
docker-compose run front npx [email protected] 
#S'il s'agit de la version3, une erreur se produira sauf s'il s'agit d'un répertoire vide, la version est donc spécifiée.

#L'écran de sélection suivant apparaîtra.

 #J'aime le nom de l'application, donc ça va!Ce sera le titre une fois ouvert sur le navigateur
? Project name                   --> sample_app

 #J'aime la description de l'application, donc ça va!Il devient un sous-titre lorsqu'il est ouvert sur le navigateur
? Project description            --> sample_app

 #Créateur d'application, je l'aime donc c'est OK!
? Author name                    --> me

 #Vous pouvez choisir npm ou yarn, mais le fil semble être plus rapide, alors sélectionnez le fil
? Choose the package manager     --> Yarn

? Choose UI framework            --> Vuetify.js
? Choose custom server framework --> None
? Choose Nuxt.js modules         --> Axios
? Choose linting tools           --> -
? Choose test framework          --> None
? Choose rendering mode          --> SPA

Connaissance des haricots

** docker-compose run **: signifie exécuter la commande suivante sur votre machine Docker ** front **: signifie exécuter sur un conteneur avec ce nom

Lorsque vous voulez taper la commande Rails

docker-compose run back rails db:create

Au fait, si vous voulez aller dans un conteneur et déboguer

docker-compose exec back sh

À


Bonjour nuxt

docker-compose up front

Lancez l'image de devant que vous venez de créer. http://localhost:8080/

Accédez à l'URL ci-dessus et lorsque cet écran s'affiche, c'est terminé! nuxt helloworld.png

hello, Rails

Ce but

créer une application de rails sous le dos Bonjour le monde avec des rails! Yay!

...Abréviation
front
├─Dockerfile
├─Gemfile
├─Gemfile.lock
...Abréviation
├─app //Où le contrôleur et la vue sont inclus
├─config //Où il y a quelque chose qui est lu au démarrage
├─db //informations de table de base de données, etc.
├─environments //Variables d'environnement pour les informations de connexion à la base de données
...Abréviation

Créer une application Rails

./


#Créez en mode API.--Si vous supprimez l'API, les éléments nécessaires au dessin de l'écran tels que la vue seront également installés.
#Sélectionnez MySQL comme base de données.

docker-compose run back rails new . -f -d mysql --api
docker-compose build

Dans cet état, le contenu du Gemfile a déjà été réécrit à partir de l'état initial. S'il te plaît vérifie le.

Paramètres de base de données

yml:./back/config/database.yml


default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: <%= ENV.fetch('MYSQL_USER') { 'root' } %> #ajouter.
  password: <%= ENV.fetch('MYSQL_PASSWORD') { 'password' } %> #ajouter.
  host: db #changement.

Accordez des autorisations à l'utilisateur décrit dans db.env.

./


touch ./back/db/grant_user.sql

sql:./back/db/grant_user.sql


GRANT ALL PRIVILEGES ON *.* TO 'username'@'%';
FLUSH PRIVILEGES;

./


#Démarrez le conteneur.
docker-compose up

#Exécutez le SQL ci-dessus dans le conteneur db.
docker-compose exec db mysql -u root -p -e"$(cat back/db/grant_user.sql)"

#Création de DB.
docker-compose run back rails db:create

Bonjour Rails

http://localhost:3000/ Accès à! Si vous voyez l'écran familier ci-dessous, vous avez réussi.

rails helloworld.png

Obtenez des utilisateurs utilisant l'API entre Nuxt-> Rails

À partir de là, passons à l'implémentation. Autant que possible, j'ai facilité l'ajout de fonctions par la suite, donc Si vous souhaitez ajouter une autre nouvelle fonction, essayez-la de la même manière.

Créons une table Users dans DB

./


docker-compose run back rails g scaffold user name:string
#Il crée divers fichiers comme celui-ci.
Running via Spring preloader in process 20
      invoke  active_record
      create    db/migrate/20200902105643_create_users.rb
      create    app/models/user.rb
      invoke    test_unit
      create      test/models/user_test.rb
      create      test/fixtures/users.yml
      invoke  resource_route
       route    resources :users
      invoke  scaffold_controller
      create    app/controllers/users_controller.rb
      invoke    test_unit
      create      test/controllers/users_controller_test.rb

# db/Ci-dessous migrer~create_users.Il exécute rb et crée une table dans la base de données.
#Une fois exécuté, le même fichier ne sera pas réexécuté.
# 2020~Si la partie numérique de est modifiée, elle peut être réexécutée, mais si la même table existe dans le DB, une erreur se produira.
docker-compose run back rails db:migrate

Vous avez maintenant une table appelée users dans une base de données appelée app_development. Facile!

Obtenons les données des utilisateurs

http://localhost:3000/users/ Accédons à. Comme il est en mode API, vous devriez voir un json vide sur un écran vide.

Pourquoi l'écran ressemble-t-il à ceci? C'est, Il y a un secret dans **. / Back / config / routes.rb **.

rb:./back/config/routes.rb


Rails.application.routes.draw do
  resources :users
end

Il y a une description de: utilisateurs dans les ressources. Il relie un contrôleur appelé ./back/app/users_controller.rb avec un chemin comme ** / users **. Par conséquent, il est facile de penser que la même procédure est utilisée lors de l'ajout de fonctions.

./


#Avec cette commande, vous pouvez vérifier quelle route est actuellement enregistrée.
docker-compose run back rails routes

Je vais omettre les détails, mais j'apprécierais que vous puissiez le vérifier dans le tutoriel, etc.

Faisons référence aux données des utilisateurs de Nuxt

Préparation

La communication entre nuxt et rails nécessite une certaine préparation. Ne nous précipitons pas.

Installez @ nuxtjs / axios

Un plugin appelé axios est utilisé pour la communication API.

./


docker-compose run front yarn 
docker-compose run front yarn add @nuxtjs/axios

Notez que ce qui suit a été ajouté à ./front/package.json:

json:./front/package.json


...
    "@nuxtjs/axios": "^5.12.2"
...

Modifier ./front/nuxt.config.js

Modifiez nuxt.config.js, qui est le fichier de configuration qui est chargé lorsque nuxt est démarré pour la première fois.

javascript:nuxt.config.js


...
  modules: [
    '@nuxtjs/axios' //ajouter à
  ],
...

Ajout de ./front/plugins/axios.js

Créez un nouveau fichier appelé axios.js sous ./front/plugins/.

javascript:./front/plugins/axios.js


import axios from "axios"

export default axios.create({
  baseURL: "http://localhost:3000"
})

Ajout de rack-cors à ./back/Gemfile

./back/Gemfile


...
gem 'rack-cors' #ajouter à
...

./


docker-compose build

Ajouter des paramètres à ./back/config/initializers/cors.rb

rb:./back/config/initializers/cors.rb


Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins '*'

    resource '*',
             headers: :any,
             methods: %i[get post put patch delete options head]
  end
end

./


docker-compose up

Développement d'écran

Créons en fait un nouvel écran. Créez un nouveau users.vue sous ./front/pages.

vue:./front/pages/users.vue


<template>
  <v-container>
    <v-row align="center" justify="center">
      <v-col cols="12">
          <h1>Hello, Qiita! </h1>
        </v-col>
      </v-row>

      <v-card
        class="mx-auto"
        max-width="300"
        tile
      >
          <v-list rounded>
            <v-subheader>USERS</v-subheader>
            <v-list-item-group color="primary">
              <v-list-item
                v-for="user in users"
                :key="users.id"
                @click=""
              >
                <v-list-item-content>
                  <v-list-item-title v-text="user.name"></v-list-item-title>
                </v-list-item-content>
              </v-list-item>
            </v-list-item-group>
          </v-list>
      </v-card>
    </v-container>
</template>
<script>
import axios from "~/plugins/axios"

export default {
  data() {
    return {
      users: []
    }
  },
  created() {
    //Attirez les utilisateurs avec axios
    axios.get("/users").then(res => {
      if (res.data) {
        this.users = res.data
      }
    })
  }
}
</script>

Ajoutons les données des utilisateurs de Nuxt

J'ai les données Utilisateurs ci-dessus ... mais elles ne devraient rien afficher car elles ne contiennent rien. Maintenant, sauvegardons les données dans la base de données avec l'API.

vue:./front/pages/users.vue


<template>
  <v-container>
    <v-row align="center" justify="center">
      <v-col cols="12">
        <v-text-field
        label="Username"
        v-model="name"
        prepend-icon=""
        type="text"
        />
        <v-btn color="primary" @click="createUser">ADD USER</v-btn>
      </v-col>
      <v-col cols="12">
          <h1>Hello, Qiita! </h1>
        </v-col>
      </v-row>

      <v-card
        class="mx-auto"
        max-width="300"
        tile
      >
          <v-list rounded>
            <v-subheader>USERS</v-subheader>
            <v-list-item-group color="primary">
              <v-list-item
                v-for="user in users"
                :key="users.id"
                @click=""
              >
                <v-list-item-content>
                  <v-list-item-title v-text="user.name"></v-list-item-title>
                </v-list-item-content>
              </v-list-item>
            </v-list-item-group>
          </v-list>
      </v-card>
    </v-container>
</template>

<script>
import axios from "~/plugins/axios"

export default {
  data() {
    return {
      name: "",
      users: []
    }
  },
  created() {
    //Attirez les utilisateurs avec axios
    axios.get("/users").then(res => {
      if (res.data) {
          this.users = res.data
          }
        })
  },
  methods: {
    //Enregistrer les utilisateurs avec axios
    createUser(){
      axios.post("/users", {name: this.name})
    .then(res => {
      if (res.data) {
          this.users.push(res.data)
          }
        })
      }
  }
}
</script>

nuxt add user.png

Vous pouvez maintenant enregistrer l'utilisateur. L'a fait! À propos, l'écran de nuxt devient blanc lorsque le thème sombre de nuxt.config.js est défini sur false.

Test automatisé

Maintenant, configurons et ajoutons un test automatisé!

Ajout de rspec-rails et factory_bot_rails à ./back/Gemfile

./back/Gemfile


...
gem 'rspec-rails' #ajouter à
gem 'factory_bot_rails' #ajouter à
...

./


docker-compose down
docker-compose build back
docker-compose up
docker-compose exec back rails generate rspec:install

#Les fichiers suivants seront ajoutés
Running via Spring preloader in process 18
      create  .rspec
      create  spec
      create  spec/spec_helper.rb
      create  spec/rails_helper.rb

Écrivons un test pour les utilisateurs

Commencez par créer un fichier de test.

./


mkdir ./back/spec/models
mkdir ./back/spec/requests
mkdir ./back/spec/factories

touch ./back/spec/models/user_spec.rb
touch ./back/spec/requests/user_spec.rb
touch ./back/spec/factories/users.rb

rb:./back/spec/models/user_spec.rb


require 'rails_helper'

RSpec.describe User, type: :model do
  it 'Test normal' do
    @user = User.new(
      name: 'test'
    )
    expect(@user).to be_valid
  end
end

rb:./back/spec/factories/users.rb


# frozen_string_literal: true

FactoryBot.define do
  factory :user do
    name { 'testuser' }
  end
end

rb:./back/spec/requests/user_spec.rb


require 'rails_helper'

RSpec.describe User, type: :request do
  # frozen_string_literal: true

  require 'rails_helper'

  describe 'User' do
    before(:each) do
      @status_code_ok = 200
    end
    it 'Afficher l'utilisateur' do
      @user = FactoryBot.create(:user)
      get '/users/'
      @json = JSON.parse(response.body)
      #Juger si une réponse est possible ou non
      expect(response.status).to eq(@status_code_ok)
    end
  end
end

./


docker-compose run back bundle exec rspec

..

Finished in 0.13418 seconds (files took 2.18 seconds to load)
2 examples, 0 failures

L'a fait. Le test est réussi. Vive le bon travail.

Test automatique avec CircleCI

Ensuite, laissez CircleCI tester automatiquement le test créé ci-dessus chaque fois que vous le poussez avec git!

Lier le compte CircleCI au référentiel git

Avez-vous créé un compte CircleCI? Si votre compte CircleCI est lié à votre compte git, comme indiqué dans l'image Vous verrez un bouton SetUp pour votre référentiel, appuyez dessus!

CircleCI 連携.png CircleCI 連携2.png

Appuyez sur Ajouter une configuration pour créer et générer une demande d'extraction pour ce référentiel.

CircleCI プルリク.png

Fusionnez-le dans master et tirez-le localement avec la commande git pull. Après l'extraction, .circleci / config.yml a été généré avec succès localement. Dans CircleCI, ce fichier config.yml est modifié pour contrôler les tests automatiques et le déploiement automatique.

Demandez à CircleCI d'exécuter un test automatisé.

Ajoutez ce qui suit à la partie test de database.yml.

yml:./back/config/database.yml


test:
  <<:         *default
  database:   app_test
  username:   root #ajouter à
  password:   rootpassword #ajouter à

Il est maintenant temps que CircleCI exécute les tests automatisés. Remplacez config.yml par la description suivante et poussez-le vers git.

yml:./circleci/config.yml


version:                     2.1

#Tâche à exécuter
jobs:
  #travail à construire
  build:
    machine:
      image:                 circleci/classic:edge
    steps:
      - checkout
      - run:
          name:              docker-compose build
          command:           docker-compose build
  #travail à tester
  test:
    machine:
      image:                 circleci/classic:edge
    steps:
      - checkout
      - run:
          name:              docker-compose up -d
          command:           docker-compose up -d
      - run:                 sleep 30
      - run:
          name:              docker-compose run back rails db:create RAILS_ENV=test
          command:           docker-compose run back rails db:create RAILS_ENV=test
      - run:
          name:              docker-compose run back rails db:migrate RAILS_ENV=test
          command:           docker-compose run back rails db:migrate RAILS_ENV=test
      - run:
          name:              docker-compose run back bundle exec rspec spec
          command:           docker-compose run back bundle exec rspec spec
      - run:
          name:              docker-compose down
          command:           docker-compose down

#Workflow pour contrôler la commande
workflows:
  build_and_test_and_deploy:
    jobs:
      - build
      - test:
          requires:
            - build

L'a fait! C'est un succès! CircleCI success.png

C'est tout pour les besoins de cet article. Je vous remercie pour votre travail acharné.

finalement

Je vous remercie pour votre travail acharné. Je suis désolé que ça fait si longtemps. J'ai écrit cet article avec l'espoir qu'il y aurait un article qui créerait un environnement qui pourrait être facilement développé immédiatement. Puisqu'il est lié à CircleCI, je pense que le développement piloté par les tests peut être réalisé immédiatement dans cet environnement. Ce ne sont que des exemples, donc je pense qu'il y a une meilleure structure et un meilleur style d'écriture. Dans ce cas, essayez de l'implémenter vous-même, et si vous pensez "c'est mieux!", Je vous serais reconnaissant de bien vouloir commenter.

Si j'ai le temps, je pense que je les rédigerai ensuite pour le déploiement en production à l'aide d'ECS dans l'environnement AWS. Ensuite, je pense que je vais finir d'écrire sur IaC avec terraform.

Recommended Posts

[Partie 1] Testez et déployez automatiquement les services WEB créés avec Rails + Nuxt + MySQL + Docker avec ECS / ECR / CircleCI pour terraformer
[Partie 2] Testez et déployez automatiquement les services WEB créés avec Rails + Nuxt + MySQL + Docker avec ECS / ECR / CircleCI pour terraformer
[AWS] Comment déployer automatiquement une application Web créée avec Rails 6 sur ECR / ECS à l'aide de CircleCI (1) Préparation [Déploiement de conteneur]
Attendez que PostgreSQL démarre avec Docker, puis démarrez le service WEB
Déployer sur heroku avec Docker (Rails 6, MySQL)
[Pour les super débutants (plus de pression)] Déploiement automatique sur AWS ECR / ECS avec Ruby2.6 x Rails6 x CircleCi [format pratique]
[Rails] [Docker] Le copier-coller est OK! Comment créer un environnement de développement Rails avec Docker