エンジニアを目指す日常ブログ

日々勉強したことのメモ。間違っていたら教えてください。

npm installでのパッケージインストールが上手くいかないときにやったことメモ

はじめに

今回の記事の目的

APIで値を取得するHTTP クライアントaxiosをインストールしたくて、npm install axiosを実行したところエラーとなった。解決した方法のメモ。

発生事象

npm install axiosを実行するとこんなエラー。

npm WARN deprecated @hapi/bourne@1.3.2: This version has been deprecated and is no longer supported or maintained
npm WARN deprecated @hapi/hoek@8.5.1: This version has been deprecated and is no longer supported or maintained
npm WARN deprecated @hapi/address@2.1.4: Moved to 'npm install @sideway/address'
npm WARN deprecated @hapi/topo@3.1.6: This version has been deprecated and is no longer supported or maintained
npm WARN deprecated sane@4.1.0: some dependency vulnerabilities fixed, support for node < 10 dropped, and newer ECMAScript syntax/features added
npm WARN deprecated urix@0.1.0: Please see https://github.com/lydell/urix#deprecated
npm WARN deprecated resolve-url@0.2.1: https://github.com/lydell/resolve-url#deprecated
npm WARN deprecated querystring@0.2.0: The querystring API is considered Legacy. new code should use the URLSearchParams API instead.
npm WARN deprecated core-js@2.6.12: core-js@<3.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Please, upgrade your dependencies to the actual version of core-js.
npm WARN deprecated fsevents@1.2.13: fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.
npm WARN deprecated @types/anymatch@3.0.0: This is a stub types definition. anymatch provides its own type definitions, so you do not need this installed.
npm WARN deprecated flatten@1.0.3: flatten is deprecated in favor of utility frameworks such as lodash.
npm WARN deprecated babel-eslint@10.1.0: babel-eslint is now @babel/eslint-parser. This package will no longer receive updates.
npm WARN deprecated querystring@0.2.1: The querystring API is considered Legacy. new code should use the URLSearchParams API instead.
npm WARN deprecated chokidar@2.1.8: Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.
npm WARN deprecated uuid@3.4.0: Please upgrade  to version 7 or higher.  Older versions may use Math.random() in certain circumstances, which is known to be problematic.  See https://v8.dev/blog/math-random for details.
npm WARN deprecated rollup-plugin-babel@4.4.0: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-babel.
npm WARN deprecated @hapi/joi@15.1.1: Switch to 'npm install joi'
npm WARN rm not removing /app/node_modules/.bin/jest as it wasn't installed by /app/node_modules/jest
npm WARN rm not removing /app/node_modules/.bin/rimraf as it wasn't installed by /app/node_modules/rimraf
npm WARN rm not removing /app/node_modules/.bin/uuid as it wasn't installed by /app/node_modules/uuid
npm WARN rm not removing /app/node_modules/.bin/semver as it wasn't installed by /app/node_modules/semver
npm WARN rm not removing /app/node_modules/.bin/mkdirp as it wasn't installed by /app/node_modules/mkdirp
npm WARN rm not removing /app/node_modules/.bin/json5 as it wasn't installed by /app/node_modules/json5
npm WARN rollback Rolling back param-case@3.0.4 failed (this is probably harmless): ETXTBSY: text file is busy, rmdir '/app/node_modules/param-case/node_modules'
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@^2.1.2 (node_modules/jest-haste-map/node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.3.2: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@^1.2.7 (node_modules/chokidar/node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.13: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@^2.1.2 (node_modules/jest-haste-map/node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.3.2: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@^2.1.3 (node_modules/react-scripts/node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.3.2: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@^1.2.7 (node_modules/watchpack-chokidar2/node_modules/chokidar/node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.13: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@^1.2.7 (node_modules/webpack-dev-server/node_modules/chokidar/node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.13: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
npm WARN @babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.15.4 requires a peer of @babel/core@^7.13.0 but none is installed. You must install peer dependencies yourself.

npm ERR! code EPERM
npm ERR! syscall rename
npm ERR! path /app/node_modules/param-case
npm ERR! dest /app/node_modules/.param-case.DELETE
npm ERR! errno -1
npm ERR! Error: EPERM: operation not permitted, rename '/app/node_modules/param-case' -> '/app/node_modules/.param-case.DELETE'
npm ERR!  [OperationalError: EPERM: operation not permitted, rename '/app/node_modules/param-case' -> '/app/node_modules/.param-case.DELETE'] {
npm ERR!   cause: [Error: EPERM: operation not permitted, rename '/app/node_modules/param-case' -> '/app/node_modules/.param-case.DELETE'] {
npm ERR!     errno: -1,
npm ERR!     code: 'EPERM',
npm ERR!     syscall: 'rename',
npm ERR!     path: '/app/node_modules/param-case',
npm ERR!     dest: '/app/node_modules/.param-case.DELETE'
npm ERR!   },
npm ERR!   errno: -1,
npm ERR!   code: 'EPERM',
npm ERR!   syscall: 'rename',
npm ERR!   path: '/app/node_modules/param-case',
npm ERR!   dest: '/app/node_modules/.param-case.DELETE',
npm ERR!   parent: 'app'
npm ERR! }
npm ERR!
npm ERR! The operation was rejected by your operating system.
npm ERR! It is likely you do not have the permissions to access this file as the current user
npm ERR!
npm ERR! If you believe this might be a permissions issue, please double-check the
npm ERR! permissions of the file and its containing directories, or try running
npm ERR! the command again as root/Administrator.

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/node/.npm/_logs/2021-09-27T08_36_43_225Z-debug.log

The operation was rejected by your operating system.と言っているが何故。

解決策

いろいろと試したがうまくいかず、最終的に実施したのは

  • node_modulesの削除
  • npmではなくyarnでインストールする

の2点。

node_modulesの削除

node_modulesフォルダを削除。

$ rm -rf node_modules/

yarn.lockの削除

yarn.lockファイルも削除。

$ rm yarn.lock

yarn.lockとは

そもそもyarnとは、npmの後継となるパッケージマネージャ。
create-react-appのコマンドは、yarnがインストールされている場合はでnpmではなくyarnを利用するとのこと。

yarn.lockファイルは、パッケージのバージョンを管理するためのlockファイル。

lockファイルは 「依存関係まで含めて、実際にどのバージョンがインストールされているか」 を管理します。 それぞれのライブラリのversionの項目がそれにあたります。 パッケージマネージャーは基本的に、lockファイルがあればそちらの記載に従うので、lockファイルを共有することで 「誰がインストールしても同じバージョンがインストールされる」 ことを担保することができます。 【npm,yarn】今さら聞けないlockファイル

yarnを利用する場合はyarn.lockを、npmを利用する場合はpackage-lock.jsonをlockファイルとして利用する。

npm installとyarn addの両方を使っていると、どちらか片方を使った方がよいといった旨の警告が出ます。 なぜかというとnpmはpackage-lock.jsonを、yarnはyarn.lockを参照するため、人によっては異なったバージョンがインストールされる可能性があるからです。【npm,yarn】今さら聞けないlockファイル

今後はパッケージのインストールの際はyarnを使ったほうが良いのかもしれない。

nodeの再インストール

yarnを使ってnodeを再インストールした。

$ yarn install

axiosのインストール

yarnを利用してインストール。

$ yarn add axios

axiosをインストールできた。

考察

過去のプロジェクトフォルダを確認すると、yarn.lockファイルではなくpackage-lock.jsonが配置されていた。 今のプロジェクトだけはyarn.lockが配置されていたので、yarnでインストールが必要だったと思われる。

過去のプロジェクトの違いで思い当たるのは、過去プロジェクトでは create-react-appコマンドでプロジェクトを作成していたが、今のプロジェクトはTypeScriptを利用するため--template typescriptオプションを追加したこと。

おわりに

根本原因は不明な点も多いが、今後はnpmを使っているのかyarnを使っているのか意識することにする。

【.dockerignore】dockerイメージビルド時に、特定のフォルダをコピー対象から外す方法メモ

はじめに

以下の記事にて、Dockerfileに各種命令を記載してDockerイメージをビルドした。 tomiko0404.hatenablog.com

このやり方では、 COPYコマンドで指定したフォルダ配下すべてのファイルがdockerイメージ作成時にコピーされる。

今回はコピーしたくないフォルダがある時に、.dockerignoreファイルを作成してコピー対象から除外する方法を実践する。

前提

フォルダ構成は以下。Dockerfile上にCOPY ./app /appの記載があるため、./app以下のフォルダがすべてコピーされてしまうが、node_modulesフォルダはコピーしたくない。

※ECSでNode.jsを動かすのであればnode_modulesはこのフォルダに不要だが、お試しでローカルでNode.jsを起動したかったためインストールしてしまった。

React-practice-6
├── Dockerfile
└── app
    ├── node_modules(コピーしたくないフォルダ。中身は省略)
    ├── package.json
    ├── public
    │   └── index.html
    └── src
        └── index.js

実施内容

.dockerignoreファイルの作成

Dockerfileと同じ階層に.dockerignoreファイルを作成し、以下の内容を記載した。

app/node_modules

.dockerignoreファイルの作成ルール

  • .dockerignoreファイルはビルドコンテキストルートに配置する。
  • 中身のパスはすべて.dockerignoreが置かれているパスからの相対パスで記載する。

参考資料
.dockerignoreが効かない?.gitignoreとは書き方が違うよ! - Qiita

ビルドコンテキストルートとは

docker buildする際に指定するパスがビルドコンテキストルートとなる。 今回、

$ sudo docker build -t react-practice-6 .

でビルドしているため.(Dockerfileがあるフォルダ)がビルドコンテキストルートとなる。

参考資料
Dockerのビルドコンテキスト(build context)について確認したときのメモ - Qiita

おわりに

.dockerignoreファイルを利用して、不要なファイルをdockerイメージ作成時のCOPY対象から外すことができた。

最終的な構成は以下となった。

React-practice-6
├── Dockerfile
├── .dockerignore
└── app
    ├── node_modules(コピーしたくないフォルダ。中身は省略)
    ├── package.json
    ├── public
    │   └── index.html
    └── src
        └── index.js

ECS(Fargate)でReactアプリを起動する方法メモ

はじめに

今回の記事の目的

nginxを利用した簡単なアプリをコンテナ上で起動することができたので、今回はECSのコンテナにReactアプリを載せることにする。

nginxを利用した簡単なアプリをコンテナ上で起動した方法
tomiko0404.hatenablog.com

環境

ローカル環境でdockerイメージを作成する

以前(vagrant上にdockerコンテナを立ち上げる方法メモ - エンジニアを目指す日常ブログ)、dockerでReactアプリを作成した際は、

  • docker-composeを利用
  • vagrant上のワークスペースとdocker上のフォルダを同期する設定volumesを入れている
  • dockerコンテナ上で、React(Nodeプロジェクト)のインストールや実行(npm start)を実施

としていたが、今回はECS(Fargate)で構築するため、dockerコンテナに入れないし、ローカル環境とフォルダ同期もできない。

そこで、Dockerfile上に

  • ソースコードをdocker上にコピー
  • 必要なNodeモジュールのインストール
  • プロジェクトの実行

を記載して指示する必要がある。

フォルダ構成

プロジェクトフォルダのフォルダ構成は以下。

React-practice-6
├── Dockerfile
└── app
    ├── package.json
    ├── public
    │   └── index.html
    └── src
        └── index.js

Dockerfileの中身

Dockerfileの中身は以下。

FROM node:14.15.4-slim

RUN apt-get update && apt-get install -y locales \
    && locale-gen en_US.UTF-8 \
    && localedef -i en_US -f UTF-8 en_US.UTF-8 \
    && echo "export LC_ALL=en_US.UTF-8" >> ~/.bashrc \
    && ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime

COPY ./app /app

WORKDIR /app

RUN npm install

ENV PORT 80

CMD ["npm", "start" ] 

RUN apt-get install -y \
    wget \
    curl \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

ポイントとして、COPYコマンドやRUNコマンドは、dockerイメージをビルドする際に一度だけ実行される。一方で、CMDコマンドは、コンテナを起動するたびに実行される。 そのため

#  NG例
RUN npm start

と記載するとビルドが上手くいかなかった。

以下コマンドで、vagrant./appフォルダの中身をコンテナ上の/appフォルダにコピーする。

COPY ./app /app

ここで、1つ目の引数(ローカルのフォルダ)には、

  • 絶対パスは利用不可
  • カレントフォルダより上のフォルダは設定負荷

という制約がある。

次に以下コマンドで、フォルダ移動する。

WORKDIR /app

これを忘れるとコンテナ上でpackage.jsonが見つからないのでエラーとなる。

Nodeをインストールする。

RUN npm install

これはイメージのビルド時に実行で問題ない。

次に環境変数の設定を実施。

ENV PORT 80

Nodeプロジェクトを実行したときにポート80でアクセスできるようになる。

最後にプロジェクトの実行コマンド。

CMD ["npm", "start" ] 

これは起動コマンドなので、コンテナ起動時に実行してほしいものである。

【補足】appフォルダ内にコピーしたくないファイルがある場合

.dockerignoreファイルを作成する必要がある。 tomiko0404.hatenablog.com

dockerイメージのビルド・ECRプッシュ・タスク起動

あとは前回の記事と同じように実施していけばOK。

nginxを利用した簡単なアプリをコンテナ上で起動した方法
tomiko0404.hatenablog.com

イメージをビルドする。

$ sudo docker build -t react-practice-6 .
$ sudo docker images

ECRにリポジトリを作成し、「pushコマンドの表示」に従って実施する。

ただし、イメージにタグをつける手順は

$ docker tag 第1引数 第2引数

のコマンドのうち第1引数部分を自分で決めたイメージ名に変更する必要がある。

// 例
$ docker tag react-practice-6 xxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/ecr-react-practice-6:latest

ECSのタスク立ち上げは前回の記事通りで問題ないが、ソースコードを変更した場合は、

  • dockerイメージの再ビルド
  • dockerイメージへのタグ付け
  • ECRへの再プッシュ
  • タスクの立ち上げ直し

が必要となる。

おわりに

ECS Fargate上にReactアプリを立ち上げることができた。 基本を習得するためにDockerfileのみで実施したが、編集するたびにビルドをやり直すのは大変そう。

AWSでもdocker-composeを利用できる機能がリリースされているようなので、使ったほうがよさそう。

Docker Compose と Amazon ECS を利用したソフトウェアデリバリの自動化 | Amazon Web Services ブログ

参考:その他のファイルの中身

あくまで動作確認用の簡易アプリ。index.js以外は、テンプレートそのままである。 ローカルでnpx create-react-appすれば最低限のファイルは作ってくれる。

dockerコンテナ(nodeイメージ)上でReactアプリを作る - エンジニアを目指す日常ブログ

  • index.js
import React from 'react';
import ReactDOM from 'react-dom';

ReactDOM.render(
  <React.StrictMode>
    <h1>React-Practice-6</h1>
    <h2>app edit</h2>
  </React.StrictMode>,
  document.getElementById('root')
);
  • index.html  ※
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <!--
      manifest.json provides metadata used when your web app is installed on a
      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
    -->
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <!--
      Notice the use of %PUBLIC_URL% in the tags above.
      It will be replaced with the URL of the `public` folder during the build.
      Only files inside the `public` folder can be referenced from the HTML.

      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
      work correctly both with client-side routing and a non-root public URL.
      Learn how to configure a non-root public URL by running `npm run build`.
    -->
    <title>React App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->
  </body>
</html>
  • package.json ※前に作ったアプリからコピーしてきたもの。必要な記載はアプリによって変わるのであくまで参考。
{
  "name": "jakee-atomic-design",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.11.4",
    "@testing-library/react": "^11.1.0",
    "@testing-library/user-event": "^12.1.10",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-router-dom": "^5.3.0",
    "react-scripts": "4.0.3",
    "recoil": "^0.4.1",
    "styled-components": "^5.3.1",
    "web-vitals": "^1.0.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

ECS(Fargate)でコンテナを起動する方法メモ

はじめに

今回の記事の目的

ECS(Fargate)を使ってdockerコンテナを立ち上げ、自分のWebアプリを起動する。ECRを利用してdockerイメージを管理する。

前提

  • AWSマネジメントコンソールにアクセスできること。
  • IAMユーザに対し、必要なAWSサービスの利用を許可するIAMロールが紐づいていること。
  • ローカル環境にdockerがインストールされていること。(※)
  • ローカル環境にdockerイメージが作成されていること。(※) (※)今回はEC2を利用。

環境

  • ローカル環境(開発環境):EC2(Linux)にsshログイン
  • dockerイメージ:nginx

EC2上のdocker環境構築
EC2でサーバを立ち上げて、SSHでサーバに入る方法メモ - エンジニアを目指す日常ブログ
dockerイメージの作成
EC2サーバ(Linux)上でdockerコンテナを起動する方法メモ - エンジニアを目指す日常ブログ

ECRへのdockerイメージ保存方法メモ

aws CLIをインストール

公式ガイド(Installing, updating, and uninstalling the AWS CLI version 2 on Linux - AWS Command Line Interface)に従いaws CLIをインストールする。

$ curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
$ unzip awscliv2.zip
$ sudo ./aws/install
$ aws --version

awsCLIの基本設定(aws configure設定)

公式ガイド( 設定の基本 - AWS Command Line Interface )に従ってaws CLIの認証情報を設定する。

IAM認証情報の設定

アクセスキー ID とシークレットアクセスキーを取得する。

AWSマネジメントコンソールのIAMコンソール→ユーザ→自分のIAMユーザ→「認証情報」タブ→「アクセスキーの作成」

アクセスキー ID とシークレットアクセスキーはメモorCSVダウンロードしておく。

awsCLIの基本設定

以下コマンドを実行すると「アクセスキーID」「シークレットアクセスキー」「リージョン」「出力形式」を対話型で設定可能。

$ aws config

リージョンはとりあえず東京でap-northeast-1、出力形式はjsonにした。

ECRにリポジトリ設定

以下の動画をベースに実施。この通りにやって失敗したところもあるのでその時実施したことも記載している。
【AWS 入門】ECS(Fargate)とECRで楽々コンテナからHelloWorldしよう! - YouTube]

マネジメントコンソールから「ECR」を検索してリポジトリ」ページ→「リポジトリの作成」。 今回は名前をhello-world-ecs-test(dockerイメージ名と同じ)として作成。

dockerイメージをECRにプッシュ

ECRはGitのようにdockerイメージを管理できる機能と思えば良いらしい。

プッシュコマンドを表示を押すとプッシュするためのコマンドが表示される。

クライアント認証

認証トークンを取得し、レジストリに対して Docker クライアントを認証します。

$ aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com
参考:ここで発生したエラー(IAM権限問題)

こちらのエラーに5時間ほど悩まされる。

An error occurred (AccessDenied) ・・・

結果的に、IAMロールの設定で解消できた。 フルアクセスの権限がついていたので問題ないと思ったのだが、「MFA認証をしない限り何もできないようにするロール」もついており、それが悪さをしていたようで、そのロールの紐づけを外したら解決した。詳細は確認中。

参考:ここで発生したエラー(ファイルアクセス権限)

IAMロール問題解決の後、こちらのエラーが発生。

Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Post "http://%2Fvar%2Frun%2Fdocker.sock/v1.24/auth": dial unix /var/run/docker.sock: connect: permission denied

/var/run/docker.sockファイルに実行権限が無いことが問題のようなので、実行権限をつける。 この操作により、これまでsudoをつけていたdockerコマンド操作がsudo無しで実行可能になる。

$ sudo chmod 666 /var/run/docker.sock
参考:同じことをEC2ではなくvagrant上で実施したときのエラー

エラー内容

Error saving credentials: error storing credentials - err: exit status 1, out: `Cannot autolaunch D-Bus without X11 $DISPLAY`

何かの認証情報が保存できていない状況とのこと。

passgnupg2をインストールして解決。正直詳細が全然わかっていない。

$ sudo apt-get install pass gnupg2
$ gpg2 - gen-key
$ pass init $gpg_id

参考にしたサイト
How to fix the "Cannot autolaunch D-Bus without X11 $DISPLAY" error - Anto ./ Online

gnupg2は、公開鍵と秘密鍵を生成してくれるツールらしい。

gnupg2とpassについては以下サイト等が参考になりそうだが…
GnuPG2のインストールと各種コマンド
エンジニア向けパスワード管理ツールPassを紹介します - termina.io

dockerイメージの構築

dockerイメージの構築コマンドはスキップ。(既にイメージ作成しているため)

イメージにタグをつける

構築が完了したら、このリポジトリにイメージをプッシュできるように、イメージにタグを付けます。

$ docker tag hello-world-ecs-test:latest xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/hello-world-ecs-test:latest

ここで

$ docker images

でイメージを見ると、同じイメージIDで、「REPOSITORY」の名前が異なるものが1行増えていることがわかる。

ECRにdockerイメージをプッシュ

以下のコマンドを実行して、新しく作成した AWS リポジトリにこのイメージをプッシュします。

docker push xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/hello-world-ecs-test:latest

ECRにイメージをプッシュできた。

ECRコンソール画面
ECRコンソール画面

ECSを利用したコンテナ立ち上げ

クラスター作成

ECSのマネジメントコンソールから クラスターの作成→ネットワーキングのみ

今回クラスタ名とNameタグは入れておく。詳細の設定は都度調べる必要がありそう。

タスク定義の作成

タスク定義とは、コンテナを立ち上げるときに実行する処理を書いておけるdocker-compose.ymlのイメージ。

  • FARGATEを選択
  • タスクロール:立ち上がるコンテナからほかのAWSサービスにアクセスする際は、タスクロールを設定して権限を付与する。
  • タスクの実行IAMロール:ECRにイメージをおいているので、アクセスする必要がある。 プラス、コンテナのログをCloud Watchに吐き出す権限をつける必要がある。「新しいロールの作成」にしておけばよい。
  • コンテナの定義追加:コンテナ名は適当に
  • コンテナの定義追加:イメージ:ここに、直接Dockerfileの中身を書いても良い。ECRを使う場合はイメージの URIを記載する。
  • コンテナ定義の追加:ポートマッピングは、docker runコマンドの-p 80:80に入れた内容80を入れる。

サービスの作成

実際にコンテナを立ち上げる。 * 起動タイプはFARGATE * タスク定義は先ほど作ったタスク定義 * サービス名は適当に * タスクの数:実際に立ち上がるコンテナの数を設定できる。 * セキュリティグループは、自動で作ってくれているので名前を変えておく。コンテナへのアクセス設定。 * パブリックIPの自動割り当てはENABLEDにしておく。

タスクが立ち上がった

タスクが立ち上がった
タスクが立ち上がった

Webサイトにアクセスする

立ち上がったタスクのパブリックIPアドレスを確認して、

パブリックIPアドレス確認
パブリックIPアドレス確認

ブラウザでアクセスする。

Webサイトにアクセス
Webサイトにアクセス

コンテナの中には入れないらしい

FARGATEを使った場合、コンテナの中に入ることはできないらしい。

おわりに

ECSを使ってコンテナを立ち上げ、コンテナ上にWebサイトを構築することができた。 今回はnginxを利用した簡単なアプリをコンテナ上で起動したので、次回はコンテナにReactアプリを載せる。

疑問点

  • 結局タスクのパブリックIPアドレスにアクセスしているが、ポートマッピングの先はどこに?
  • タスクが立ち上がるとIPアドレスが変わってしまう?対策は?ロードバランサ?

EC2サーバ(Linux)上でdockerコンテナを起動する方法メモ(nginxベース)

はじめに

今回の記事の目的

EC2サーバ(Linux)上にdocker環境を構築し、コンテナを立ち上げてwebサイトを表示する。

最終的に目指したいところ

最終的には、ECS(Fargate)を使ってdockerコンテナを立ち上げ、自分のWebアプリを起動したい。

そのためには、まずローカルでdockerの環境を整える必要がある。vagrant等でローカルLinux環境を構築しても良いが、せっかくなので勉強がてら、EC2でサーバを立ち上げ、それを疑似的にローカル環境とみなしてdocker環境を構築する。

前提

  • AWSマネジメントコンソールにアクセスできること。
  • IAMユーザに対し、必要なAWSサービスの利用を許可するIAMロールが紐づいていること。
  • LinuxOSベースのEC2インスタンスにログインしていること。

EC2を立ち上げた記録 tomiko0404.hatenablog.com

実施内容

dockerをEC2にインストール

コマンドを実行しdockerをインストール。

$ sudo amazon-linux-extras install docker -y

コンテナイメージ作成

コンテナを起動する目には、コンテナの設計書となる dockerイメージ が必要となる。 Dockerfile というテキストファイルに、dockerイメージをビルドするときに実行する命令を記載する必要がある。

作業用フォルダを作成

$ mkdir ecs_test2
$ cd ecs_test2

Dockerfileを作成

viエディタでDockerfileを編集する。

$ touch Dockerfile
$ vi Dockerfile

ファイルに記載する中身は以下。

FROM nginx:latest
COPY ./src /usr/share/nginx/html

※vi操作…コピペしてEsc:wqEnter

Dockerファイルは、以下の動画を参考に記載。これ以降の流れも基本的には以下動画をベースに実施したが、失敗したところもあるのでその解決手順も追加している。
【AWS 入門】ECS(Fargate)とECRで楽々コンテナからHelloWorldしよう! - YouTube]

FROM nginx:latestの部分は、必須の記載。FROMのあとにベースとなるイメージを記載する。今回はnginxを利用。 Reactの場合は以下。(別記事にする…)

FROM node:14.15.4-slim

COPYの部分は、ローカルの./srcフォルダの中身をコンテナの/usr/share/nginx/htmlにコピーするという意味。dockerのnginxでは、Webサーバのドキュメントルートとして/usr/share/nginx/htmlが設定されているらしいので、ポート80でアクセスした際には配下のindex.htmlがデフォルト表示される。(ここは知識が曖昧。)

とりあえずCOPYの命令を入れて、Webサイトのソースをローカル(EC2)の./src内で開発しておけばOKという理解。

srcの作成

ここで./srcフォルダとindex.htmlファイルを作っておく。

$ mkdir src
$ cd src
$ touch index.html
$ vi index.html

index.htmlの中身は何でもよい。

<h1>Hello world ECS test </h1>

dockerを起動する

dockerの機能自体を起動する。

$ sudo service docker start

dockerイメージの作成

docker buildコマンドでイメージを作成する。

$ sudo docker build . -t hello-world-ecs-test

.はどこにイメージを作るかを指定している。(今いるフォルダ)
-t [イメージ名] はイメージ名の指定オプション。(今回はhello-world-ecs-test)

作成したイメージを確認する。

$ sudo docker images

こんな感じで見える。

dockerイメージ
dockerイメージ

コンテナを起動

コンテナの起動

実際にdocker runコマンドでコンテナを起動する。

$ sudo docker run --rm -p 80:80 hello-world-ecs-test

-p 80:80の意味は、ローカルのポート80にアクセスすると、dockerコンテナの内部でポート80で動いているアプリケーションに接続できるようになる、という意味。 ポートフォワーディングという機能。

--rmの意味は、以下とのこと。

デフォルトではコンテナを終了しても、コンテナのファイルシステム(の内容)を保持し続けます。そのため、デバッグはとても簡単になり(最後の状態を確認できるため)、デフォルトで全てのデータが保持されます。しかし、プロセスを短い期間だけ フォアグラウンド で動かしたとしても、これらのコンテナのファイルシステムが溜まり続ける場合があります。そうではなく、 コンテナの終了時に、自動的にコンテナをクリーンアップし、ファイルシステムを削除する には --rm フラグを追加します。 Docker run リファレンス — Docker-docs-ja 20.10 ドキュメント

(参考)EC2ではなくローカルでやる場合

もし、docker環境構築の作業をEC2ではなく自分のローカルPC上で実施するのであれば、参考動画の通り

$ sudo docker run --rm -p 8080:80 hello-world-ecs-test

でよさそう。 ローカルのポート8080にアクセスする(localhost:8080)ことで、dockerコンテナの内部でポート80で動いているアプリケーションに接続できる。(ポート8080というのは、80と似ているということで、テスト環境やローカル環境でよく使われるポートとのこと。)

Webサイトを確認する

自分のPCでブラウザを開き、[EC2のパブリックIPアドレス]:80を入力する。

パブリックIPアドレスの確認方法は以下の記事を参照
EC2でサーバを立ち上げて、SSHでサーバに入る方法メモ - エンジニアを目指す日常ブログ

Webサイトを表示できた
Webサイトを表示できた

【注意】ソースコードを編集したとき

ソースコードを編集したときは、dockerイメージの作成からやりなおす必要あり。Dockerfileで命令したCOPY処理が走るのは、イメージ作成の段階のため。

おわりに

ここまででEC2上でdocker環境を構築できた。

次は、EC2上でのdocker runではなく、ここで作ったdockerイメージを使ってECS上でコンテナを立ち上げる。

tomiko0404.hatenablog.com

【AWSに入門】EC2でサーバを立ち上げて、SSHでサーバに入る方法メモ

はじめに

今回の記事の目的

EC2サーバ(Linux)を構築し、サーバにログイン(SSHアクセス)する。

最終的に目指したいところ

最終的には、ECS(Fargate)を使ってdockerコンテナを立ち上げ、自分のWebアプリを起動したい。

そのためには、まずローカルでdockerの環境を整える必要がある。vagrant等でローカルLinux環境を構築しても良いが、せっかくなので勉強がてら、EC2でサーバを立ち上げ、それを疑似的にローカル環境とみなしてdocker環境を構築する。

前提

  • AWSマネジメントコンソールにアクセスできること。
  • IAMユーザに対し、必要なAWSサービスの利用を許可するIAMロールが紐づいていること。

EC2を利用したサーバの構築手順

VPCを作成

VPCを作成する。

AWSコンソール画面の「VPC」から「VPCを作成」を選択。

vpc作成
vpc作成画面

CIDRブロックは10.0.0.0/24とした。
意味としては

  • プライベートIPアドレス
  • IPアドレスのネットワーク部が24ビット(10.0.0 までの部分)
  • ネットワーク全体を表すIPアドレスホスト部を0としたアドレス(最後の0の部分)
  • ホスト部には、 32-24=8 ビット分、256個のアドレスを利用可能。10.0.0.1~10.0.0.254IPアドレスが利用可能。(10.0.0.255はブロードキャストアドレス)

CIDRブロックに関する記事
IPv4 CIDRブロック - Qiita CIDRブロックを計算できるサイト
CIDRをIPアドレスに展開ツール v2.0.3 -IPv46 – IPアドレス(CIDR)の範囲確認・変換・国判定サイト

サブネットを作成する

同じVPCコンソールから、サブネットタブを選んで「サブネットを作成」を選ぶ。

VPC IDは先ほど作ったVPCを設定する。

サブネット作成画面
サブネット作成画面

今回サブネットにはインターネットゲートウェイとの通信を設定して、インターネットからアクセスできるようにしたいので、名前はパブリックサブネットを表すpublic-1aとした。1aアベイラビリティゾーン(AZ)がap-northeast-1aであることを表す。(東京リージョンの1個目のAZ)

インターネットゲートウェイを作成する

同じVPCコンソールから、インターネットゲートウェイを選んで「インターネットゲートウェイの作成」を選ぶ。

インターネットゲートウェイの作成
インターネットゲートウェイの作成

次に、作成したインターネットゲートウェイにチェックマークを入れ、「アクション」→「VPCにアタッチ」。先ほど作成したVPCにアタッチする。

ルートテーブルの作成・設定

VPCコンソールから、ルートテーブルを選んで「ルートテーブルの作成」を選ぶ。 VPCは先ほど作ったVPCを選ぶ。

ルートテーブルの作成
ルートテーブルの作成

作成したルートテーブルを選び、「ルートを編集」→「ルートを追加」で、0.0.0.0/0(フルオープン)から、インターネットゲートウェイへのアクセスルートを追加する。

ルートテーブルの設定
ルートテーブルの設定

ルートテーブルを選択し、「サブネットの関連付け」→「サブネットの関連付けを編集」から、先ほど作ったサブネット(public-1a)を関連付ける。※この操作で、サブネットがいわゆる「パブリックサブネット」となる。

EC2インスタンスを起動する

マネジメントコンソールからEC2のコンソール画面に飛ぶ。「インスタンスを起動」を選ぶ。

AMIの選択

AMI選択画面では「Amazon Linux」を選択。

AMIの選択
AMIの選択

AMIとは、サーバを立ち上げるときの設定ファイルのようなもので、自分で作成することもできるし、AWS側が用意しているものを使うこともできる。また、サードパーティー製のものを買って使うこともできる。

インスタンスタイプの選択

インスタンスタイプの選択。t2.microを選んでおく。

インスタンスタイプの選択
インスタンスタイプの選択

インスタンスタイプとは、起動するサーバのスペックを表すもの。(詳細は「インスタンスタイプ」「インスタンスファミリー」で検索)

詳細を設定する

インスタンス詳細の設定
インスタンス詳細の設定

  • ネットワーク:先ほど作ったVPC
  • サブネット:先ほど作ったパブリックサブネット
  • 自動割り当てパブリックIP:有効(自動でパブリックIPアドレスをふってくれる)

ストレージの追加

デフォルト設定とする。

ストレージの追加
ストレージの追加

タグの追加

今回はNameタグのみつけておく。

タグの追加
タグの追加

セキュリティグループの設定

SSHとHTTPのポートに対し、0.0.0.0/0(フルアクセス)の権限を与えておく。おそらく実際の業務システムでは、フルアクセス設定はNG。

セキュリティグループの設定
セキュリティグループの設定

キーペアの作成

キーペアを作成し、秘密鍵をダウンロードしておく(EC2アクセス時に使用する)。

キーペアの作成
キーペアの作成

設定完了

しばらく待つとインスタンスが起動する。

EC2インスタンスへのSSHアクセス

マネジメントコンソールから、起動したEC2のパブリックIPアドレスを確認する。

パブリックIPアドレス確認
パブリックIPアドレス確認

teratermを起動し、ホストに先ほど設定したIPアドレスを入れる。

teraterm
teraterm

  • ユーザ名:ec2-user
  • RSA/DSA/・・・・鍵を使う にチェックを入れる。
  • 秘密鍵に、EC2作成時にダウンロードしておいた秘密鍵を設定する。

これでサーバにアクセスできる。 実際の業務では、こんなふうにインターネット経由で誰でもアクセスできては問題なので、違うアクセス方法を考える必要があると思われる。。

おわりに

今回はEC2インスタンスを準備し、起動した上で、SSHアクセスを行なった。 次はサーバ上にdocker環境を構築して、コンテナをEC2上に立ち上げる方法をメモする。

Gitでブランチを作成してコードを退避して、昨日の状態のコードと行き来した方法のメモ

はじめに

今回の記事の目的

Gitで作っていたアプリがうまく動作しなくなったため、Gitのブランチを利用して「昨日の状態に戻す」「修正版のアプリをマージする」ことで対処した。gitでbranchを作成してmergeして、というやり方を学んだのでメモ。

そもそもGitを導入したときの話はこちら。 tomiko0404.hatenablog.com

前提

  • ローカルのブランチ
    • master → 昨日の時点で、「ヘッダまで完成」の状態でコミット済。
  • リモートブランチ
    • master →GitHub上に存在。同じく昨日の時点で、「ヘッダまで完成」の状態でコミット済。

この状態から作業を始めたところ、不具合が発生。どこが悪いか見当がつかず。

昨日の状態に戻す

まずは、昨日の状態に戻したい。ただ、今日作成した分も消したくない。

今日作成したコードを、別ブランチに退避する

以下の構成に変更する。

  • ローカルのブランチ
    • master → 昨日の時点で、「ヘッダまで完成」の状態でコミット済。
    • miss → 今日作った分。動作に不具合あり。
  • リモートブランチ
    • master →GitHub上に存在。同じく昨日の時点で、「ヘッダまで完成」の状態でコミット済。
    • miss → 今日作った分。動作に不具合あり。

ローカルに新ブランチを作成する。

git branch miss

によりブランチの作成。

git branch

を実行すると

$ git branch
* master
  miss

missブランチが作成できている。

今日作成したコードを新ブランチにコミットする。

ここで、作成したmissブランチにチェックアウトする。

git checkout miss

今回、ブランチを作成する前に手元のファイルを更新してしまっているが、この場合、新規のブランチには変更後のファイルを保ったままcheckoutできる模様。
(あとから別フォルダで試して確認した)

こちらのサイトにもその旨記載がある。
git で 後からブランチを作成する|プログラムメモ


この状態でステージングとコミット。

git add .
git commit -m "動作不具合あり"

GitHub上に新ブランチを作成する。

ブランチを選択する画面で、新しく作りたいブランチの名前を入力し、createを押す。(画像はブランチ名を「miss2」としている)

GitHub上でブランチを作成する
GitHub上でブランチを作成する

ローカルリポジトリから、pushしておく。

git push  origin miss

昨日の状態を復元する

今日作ったコードの退避ができたので、昨日の状態をもつmasterブランチにチェックアウトする。

git checkout master

これで、フォルダ上のコードが昨日の状態に復元された。

また

git checkout miss

とすれば最新の不具合ありバージョンと行き来することができる。

バグ解消後、マージする

確認したところ、styledコンポーネントの中に書いているCSSにスペルミスを発見。missブランチ上で、スペルミスを修正することで正しいアプリを完成させることができた。

元のブランチにマージする

missブランチが正しい状態になったためmasterブランチにマージする。

missブランチ上で正しいコードをコミットしたのち、masterブランチにチェックアウトした状態で、missブランチをマージする。

git merge miss

コンフリクトの解消

mergeを実行したところ、以下のエラーが発生。

CONFLICT (content): Merge conflict in src/App.js
Auto-merging src/App.css
CONFLICT (content): Merge conflict in src/App.css
Automatic merge failed; fix conflicts and then commit the result.

ソースコードを見てみると、以下の記載が自動で追加されている。

<<<<<<< HEAD
  return (
    <BrowserRouter>
      <HeaderOnly>
・・・
      </HeaderOnly>
    </BrowserRouter>
  );
=======
  return <Router />
>>>>>>> miss

どうやら、

<<<<<<< HEAD
 衝突した部分の、マージ先(masterブランチ)のコードに書かれていた内容
=======
  衝突した部分の、マージ元(missブランチ)のコードに書かれていた内容
>>>>>>> miss

ということらしい。そこで、

  return <Router />

以外の部分は削除した。

コミットしたうえで再度マージを実行。

git add .
git commit -m "コンフリクトの解消"
git merge miss

これでmasterブランチにマージが完了した。

リモートリポジトリにもpushして、完了。

git push origin master

GitHubのmasterブランチも最新にすることができた
GitHubのmasterブランチも最新にすることができた

おわりに

今回は後からブランチを作ってしまったが、本来であれば、問題なく動いているmasterブランチに対し、開発用のdevelopブランチで開発を進め、mergeするのが本来の使い方な気がする。

Gitは奥深そうなので再度勉強が必要そう。
第2話 ブランチとは?ポインタってどういう意味?作成・確認・切り替え方法【連載】マンガでわかるGit ~コマンド編~ - itstaffing エンジニアスタイル

感想

不具合が直ってよかった。じゃけえさんのAtomic-design講座完了。

じゃけえさんのAtomic-design講座完了
じゃけえさんのAtomic-design講座完了