さくらVPSのスタートアップスクリプトでマインクラフトサーバー構築

マイクラサーバーをさくらVPSで構築して、iOS(iPhone, iPad)でプレイできる環境を構築したときのメモ。

マニュアル

さくらのGaming script:Minecraft Server(統合版) に必要な手順がすべて載っている。ほかにもマニュアルがあったが、これが必要手順をすべて網羅されていた。
# さくらインターネットさんはどれを見てもマニュアルがわかりやすい

初期構築〜オペレータ権限付与

マニュアルをもとに、「オペレータ権限の設定」まで進める。

なお、オペレータ権限の設定の箇所でのハマリポイントは、権限付与するユーザーがマイクラサーバーに接続していないといけない、ということ。

ubuntu@:~$ screen -ls
There is a screen on:
        687.minecraft   (04/19/2020 01:24:15 PM)        (Detached)
1 Socket in /run/screen/S-ubuntu.

screenコマンドでマイクラのセッション名が表示される。
「$ screen -r minecraft」だけで接続できた。

ubuntu@:~$ screen -r minecraft

NO LOG FILE! - setting up server logging...
[2020-04-19 13:24:16 INFO] Starting Server
[2020-04-19 13:24:16 INFO] Version 1.14.60.5
[2020-04-19 13:24:16 INFO] Session ID e35268cf-9718-4153-a8be-14cc4abbc8b8
[2020-04-19 13:24:16 INFO] Level Name: Bedrock level
[2020-04-19 13:24:16 INFO] Game mode: 1 Creative
[2020-04-19 13:24:16 INFO] Difficulty: 1 EASY
[2020-04-19 13:24:16 INFO] opening worlds/Bedrock level/db
[2020-04-19 13:24:18 INFO] IPv4 supported, port: xxxxx
[2020-04-19 13:24:18 INFO] IPv6 not supported
[2020-04-19 13:24:18 INFO] IPv4 supported, port: xxxxx
[2020-04-19 13:24:18 INFO] IPv6 not supported
[2020-04-19 13:24:19 INFO] Server started.
op MyAuthor
No targets matched selector

「MyAuthor」というユーザー名にオペレータ権限を付与したところ、「No targets matched selector」(対象がいません)と表示されてしまった。

「MyAuthor」というユーザーで今回さくらVPSで構築したマイクラサーバーの世界に接続してMap上に放置した状態で再度コマンドを実行。

[2020-04-19 13:25:42 INFO] Player connected: MyAuthor, xuid: xxxxxxxxxxx

op MyAuthor

Opped: MyAuthor

「Opped: MyAuthor」と表示され、無事に権限付与完了。

サバイバル→クリエイティブに設定変更

オペレータ権限のあるMyAuthorユーザーの設定メニューから、ゲームモードを変更するだけ。

その他設定ファイル

さくらVPSのMinecraft Server(統合版)のスタートアップスクリプトで構築すると、「/opt/minecraft/server.properties」にマイクラの設定ファイルが設置される。

中身は以下のような形でゲームモードなど諸々の設定が変更できる。設定変更後は「$ sudo systemctl restart minecraft.service」で反映できる。面倒だったらサーバー再起動の「$ sudo reboot」でも大丈夫。

ubuntu@:~$ cat /opt/minecraft/server.properties

server-name=Dedicated Server
# Used as the server name
# Allowed values: Any string

gamemode=survival
# Sets the game mode for new players.
# Allowed values: "survival", "creative", or "adventure"

difficulty=easy
# Sets the difficulty of the world.
# Allowed values: "peaceful", "easy", "normal", or "hard"

allow-cheats=false
# If true then cheats like commands can be used.
# Allowed values: "true" or "false"

max-players=10
# The maximum number of players that can play on the server.
# Allowed values: Any positive integer

online-mode=true
# If true then all connected players must be authenticated to Xbox Live.
# Clients connecting to remote (non-LAN) servers will always require Xbox Live authentication regardless of this setting.
# If the server accepts connections from the Internet, then it's highly recommended to enable online-mode.
# Allowed values: "true" or "false"

white-list=false
# If true then all connected players must be listed in the separate whitelist.jsonfile.
# Allowed values: "true" or "false"

server-port=19132
# Which IPv4 port the server should listen to.
# Allowed values: Integers in the range [1, 65535]

server-portv6=19133
# Which IPv6 port the server should listen to.
# Allowed values: Integers in the range [1, 65535]

view-distance=32
# The maximum allowed view distance in number of chunks.
# Allowed values: Any positive integer.

tick-distance=4
# The world will be ticked this many chunks away from any player.
# Allowed values: Integers in the range [4, 12]

player-idle-timeout=30
# After a player has idled for this many minutes they will be kicked. If set to 0 then players can idle indefinitely.
# Allowed values: Any non-negative integer.

max-threads=8
# Maximum number of threads the server will try to use. If set to 0 or removed then it will use as many as possible.
# Allowed values: Any positive integer.

level-name=Bedrock level
# Allowed values: Any string

level-seed=
# Use to randomize the world
# Allowed values: Any string

default-player-permission-level=member
# Permission level for new players joining for the first time.
# Allowed values: "visitor", "member", "operator"

texturepack-required=false
# Force clients to use texture packs in the current world
# Allowed values: "true" or "false"

content-log-file-enabled=false
# Enables logging content errors to a file
# Allowed values: "true" or "false"

compression-threshold=1
# Determines the smallest size of raw network payload to compress
# Allowed values: 0-65535

server-authoritative-movement=true
# Enables server authoritative movement. If true, the server will replay local user input on
# the server and send down corrections when the client's position doesn't match the server's.
# Corrections will only happen if correct-player-movement is set to true.

player-movement-score-threshold=20
# The number of incongruent time intervals needed before abnormal behavior is reported.
# Disabled by server-authoritative-movement.

player-movement-distance-threshold=0.3
# The difference between server and client positions that needs to be exceeded before abnormal behavior is detected.
# Disabled by server-authoritative-movement.

player-movement-duration-threshold-in-ms=500
# The duration of time the server and client positions can be out of sync (as defined by player-movement-distance-threshold)
# before the abnormal movement score is incremented. This value is defined in milliseconds.
# Disabled by server-authoritative-movement.

correct-player-movement=false
# If true, the client position will get corrected to the server position if the movement score exceeds the threshold.

世界に接続できない問題

「世界に接続できませんでした」

自前マイクラサーバーに接続して以下メッセージが表示される場合、スマホ側でマイクラを再起動すると直る。

世界に接続できませんでした

挙動を正確に掴めていないが、自前マイクラサーバーの設定変更をした場合に、このエラー表示が出る確率が高いように思える。

「他のデバイスでこの世界を現在プレイしています」

おそらく、ログインセッションがサーバー側に残ってしまっているために発生する現象と思われる。

世界に参加できません。サインインしているアカウントは、他のデバイスでこの世界を現在プレイしています。

マイクラサービスを再起動する必要があるため、サーバーにログインして以下コマンドを打つと直る。

$ sudo systemctl restart minecraft.service

Xcodeで行選択するショートカットの追加設定

AtomやSublime Textみたいに1行選択するショートカットをXcodeにも割り当てる方法。

  1. Xcode起動
  2. Xcodeメニューの Preferences > Key Bindings を開く
  3. Filterと表示された検索窓で「line」と入力
  4. 「Select Line」の右側のショートカットを割り当てる箇所でダブクリックして編集モードにする
  5. 「cmd + L」と入力してEnter

  1. 「cmd + L」が「Go to Line」か「Jump to Line」か、なにかと競合するため、エラーマークが表示される。競合しているショートカットを削除するとエラーマークが消える。 

VMware fusionでmacOS Catalinaのディスプレイサイズ変更

ちょっと特殊な環境が必要で、

ホスト:macOS Catalina 10.15.3 (MacBook Pro)
 ↓ VMware Fusion 11.5.3
ゲスト:macOS Catalina 10.15.3 (仮想マシン)

というのを作ったが、ゲスト側のディスプレイサイズが1024x768しか表示されなかったので、それを修正したときのメモ。

VMware Toolsのインストール

VMwareメニューの 仮想マシン > VMware Toolsのインストール を実行する。
(以下画像はすでにインストールしてしまったため、「再インストール」と表示されている)

ゲスト側でインストールを実行し、途中で「実行許可しますか?」みたいなダイアログが表示されるため、macのセキュリティ設定でちゃんと許可しておく。

インストールしたら再起動。

VMwareのディスプレイ設定

起動しているゲストのVMwareメニューの 設定 > ディスプレイ を開き、

以下のようにRetinaディスプレイを使用するように設定する。

ゲスト側の解像度設定の追加

以降は、すべてゲスト側のmacでターミナルを開いて実行していく。
(ホスト側のmacではないため要注意)

解像度を追加

VMware公式サイトに記載されている以下のコマンドを実行する。

devuser@devusernomakku ~ % sudo /Library/Application\ Support/VMware\ Tools/vmware-resolutionSet 1600 900

参考:Mac OS X ゲストのディスプレイ設定に解像度が 1 つしか表示されない

そうすると、macのディスプレイ設定に 1600 x 900 が追加される。

HiDPIの無効化設定

1600 x 900 の解像度を設定したところ、以下動画のように解像度が適用されない。
また、以下動画で紹介されているコマンドを実行したが、うまく反映されなかった。

sudo defaults write /Library/Preferences/com.apple.windowserver DisplayResolutionEnabled -bool NO

参考:YouTube - How to Fix macOS Mojave Screen Resolution on VMware on Windows 10 & mac?

そこで以下を実行する。

devuser@devusernomakku ~ % sudo defaults delete /Library/Preferences/com.apple.windowserver.plist DisplayResolutionEnabled

macを再起動すると解像度が 1600 x 900 で適用される。

参考サイト

MacでVagrant x Ansibleを使ってRuby on Rails x Minitest自動構築

Vagrant x AnsibleでCentOS 8のRuby on Rails構築ソースがなかったため、趣味で作成して、GitHubに vagrant-ansible-ror を公開しました。

ポイント

  • Vagrantで自動的にCentos 8でRuby on Railsを構築して、構築後にMinitestまで走らせています。
  • AnsibleはFail Firstになっているため、Ansible上にはテスト実装しませんでした(コケたらわかるため)。
  • 冪等性の観点だとGemなどはバージョン固定が望ましいと思うのですが、Bundlerで依存関係を管理していることや、あくまで一時的な開発目的のため、バージョンはあえて固定しませんでした(常に最新インストール)。

環境

  • ホスト(Mac側)
    • ansible-playbook 2.9.3
    • Vagrant 2.2.6
    • macOS Catalina version 10.15.3
  • ゲスト(サーバー側)
    • Frontend: Not specified (Ruby on Rails default)
    • Application: Ruby on Rails 5
    • Middleware: PostgreSQL, Puma
    • OS: CentOS 8
  • 備考
    Ruby version 2.6.5

ハマりポイント

  1. 情報が古い
    GitHubや記述系ブログに公開されているVagrant, Ansibleのソースが古いことが多い。たとえば、rootになる設定として sudo: yes とあるが、最新版は become: yes にしないと動かない。ただし、技術系ブログに、「その情報古いですよ」という記事を書いてくれている人がたくさんいるため、解決できた。

  2. ベストプラクティスがどれかわからない
    Ansible Best Practices に一例が公開されているが、もっとたくさんの参考情報がほしかった。GitHubで探したが、どれがよいのかわからなかった。

  3. ドキュメントがまとまっていない(気がする)
    Kindle本やQiitaを記事を参考にしながら、 Ansible Documentation でキーワード検索して仕様把握する、といったことをやった。しかし、古い情報が混在しているため、StackOverflowとGitHubでソース検索(become:yesとかで検索)しながら検証といった進め方で、かなりハマった。ドキュメントの完成形は Vue.js だと思う。考え方、サンプルコード、サンプル動画、ソース解説、体系的に1から順に整理されていて上から読んでいけば一通りわかる。

  4. 最新版だとコケる
    【CentOS 8.0 (version 1905.1) だとファイル共有するためのvbguestが使えない(rsyncは使えるが、virtualboxが使えない)】
    → GitHubでIssueが切られているが、 CentOS 8 - installing Guest additions fails #367 現在は対応待ち。
    【Ruby 2.7.0 だとRuby on Rails用に必要なGem郡が対応されていない】
    → RailsアプリをRuby 2.7.0で動かして分かったこと に書かれているが、Warningの連続でMinitestすらまともに動かなかったため、バージョンを2.6.5に下げて暫定対応した。

  5. Ansible Playbookのデバッグが難しい
    Ansible Playbookの実行中に、コマンドプロンプトからの質問(削除しますか?(y/n)みたいな)があると、なにも表示されずにフリーズしてしまう。そのため、Playbookでデバッグモード(-vvv)とステップ実行(--step)しながら、フリーズした箇所で、$ vagrant ssh して実際にコマンドを打ってみて、どんな状況になっているのか確認したりと、かなり面倒だった。もしかしたら、もっとうまいやり方があるのかもしれないが、方法わからず。
    自分用のハンドブックになるが、 Ansible Playbook Command にデバッグでよく使用したコマンドを記述した。

  6. 構成管理は意外と時間がかかるし工数がかかる
    冪等性を担保する必要があるため、何度も何度も実行しては設定を修正して、というのを繰り返す必要がある。「ターミナルで打ったコマンドをただ設定するだけだから、そんなに時間かからないだろ」と思っていたが、1回目がうまくいっても2回目にコケる、状況によって環境が変わってしまうなど、冪等性の担保が難しかった。$ rails new するだけのRuby on Railsをただ構築するだけの設定なのに、数週間の工数がかかった(インフラ強いひとであればもっと早いと思うが)。
    その代わり、一度構成管理が完璧に仕上がれば、作業手順書も人手も必要なくなるため、長期手に運用する場合は、工数が大幅に減らせると感じている。

Ansible Playbookのexpectハマリポイント

シェル実行時にサーバーから入力待ち状態のコマンドプロンプトが発生した場合に、自動で応答できるようにするAnsibleの expect – Executes a command and responds to prompts がある。

いくつかハマリポイントがあるため、そのメモ。

環境

  • Macを使ってVagrant x Ansibleで構築
  • CentOS 8
  • Vagrant 2.2.6
  • ansible-playbook 2.9.3

pexpectのインストール

まずpipが必要になる。いろいろな記事で $ pip install pexpect と書かれていたが、サーバーにログインしてpipを実行すると、コマンドが見つからないと言われてしまう。

$ vagrant ssh
$ pip install pexpect
-bash: pip: command not found

pipはPythonのバージョンによって、pip2とpip3があるらしい。どれがインストールされているか確認すると、python3-pipがあったため、pip3を利用する。

$ yum list installed | grep pip
Failed to set locale, defaulting to C
libpipeline.x86_64                  1.5.0-2.el8                                     @anaconda
platform-python-pip.noarch          9.0.3-15.el8                                    @BaseOS
python3-pip.noarch                  9.0.3-15.el8                                    @AppStream

$ pip3 --version
pip 9.0.3 from /usr/lib/python3.6/site-packages (python 3.6)

$ pip3 install pexpect でインストールすればよいことがわかったため、pexpectをAnsibleのタスクでインストールする。

- name: Install pexpect for prompts
  become: yes
  shell: "pip3 install pexpect"

pexpectのタスク実行

書き方は正規表現

Ansibleのドキュメント expect には、以下のようなタスクの記載例がある。

- name: Case insensitive password string match
  expect:
    command: passwd username
    responses:
      (?i)password: "MySekretPa$$word"
  # you don't want to show passwords in your logs
  no_log: true

- name: Generic question with multiple different responses
  expect:
    command: /path/to/custom/command
    responses:
      Question:
        - response1
        - response2
        - response3

連続で質問に答える場合は、「Question」を利用し、一問一答であればそのままYML形式で書けばよい。このときに、質問はPythonの正規表現形式で記載する必要があるため、カッコやはてなマークなどの記号に注意する必要がある。

たとえばNG例として、以下のような質問をされた場合(Gemfileを上書きしますか?の質問)、

Overwrite /home/vagrant/sample-rails/Gemfile? (enter "h" for help) [Ynaqdhm]

そのまま質問をタスクに記述すると、以下のような記載になる。

[NG記載例]

- name: Rails new
  expect:
    command: "bundle exec rails new ."
    responses:
      Overwrite /home/vagrant/sample-rails/Gemfile? (enter "h" for help) [Ynaqdhm]: "Y"

この状態だと、正規表現が適用されてしまうため、うまく動かない。そこで、質問されたときの重要なキーワードだけ残して、それ以外は「(.*)」にすると、うまく動いた。

[正しい記載例]

- name: Rails new
  expect:
    command: "bundle exec rails new ."
    responses:
      (.*)Overwrite (.*)Gemfile(.*): "Y"

質問の引用符の有無

GitHubで「become yes expect rsponses」などのキーワードでソースコード検索すると、質問をダブルクォーテーションなどの引用符で囲むケースもあった。しかし、自分の場合は囲っても囲わなくても、結果は変わらなかった。ただし、挙動が変わったという記事も見かけたため、要注意。

なお、Ansibleの公式ドキュメントは引用符を囲まない形式で記載されている。

[Ansibleの公式ドキュメント]

- name: Case insensitive password string match
  expect:
    command: passwd username
    responses:
      (?i)password: "MySekretPa$$word"

[引用符で囲む例(正しい書き方なのかは不明)]

- name: Case insensitive password string match
  expect:
    command: passwd username
    responses:
      "(?i)password": "MySekretPa$$word"

タイムアウト

質問が発生するタスクの実行自体に時間がかかる場合、ちゃんと回答したとしても(たとえば、なにか大量にインストールするなどで時間がかかった場合など)、デフォルトのタイムアウト設定30秒を過ぎると途中でタイムアウトされてしまう。

たとえば、 $ rails new . を実行して、Gemfileに記載されたGemをすべてインストールするタスクを実行した場合、以下のように途中でタイムアウトになってしまう。

fatal: [192.168.33.10]: FAILED! => {
    "changed": true,
    "cmd": "bundle exec rails new .",
    "delta": "0:00:30.144455",
    "end": "2020-02-22 17:10:17.228032",
    "invocation": {
        "module_args": {
            "chdir": "/home/vagrant/sample-rails/",
            "command": "bundle exec rails new .",
            "creates": null,
            "echo": false,
            "removes": null,
            "responses": {
                "Overwrite {{ sample_rails_path }}Gemfile? (enter \"h\" for help) [Ynaqdhm]": "Y"
            },
            "timeout": 30
        }
    },
    "msg": "command exceeded timeout",
    "rc": null,
    "start": "2020-02-22 17:09:47.083577",
    "stdout": "\u001b[1m\u001b[34m       exist\u001b[0m  \r\n\u001b[1m\u001b[32m      create\u001b[0m  README.md\r\n\u001b[1m\u001b[32m      create\u001b[0m  Rakefile\r\n\u001b[1m\u001b[32m      create\u001b[0m  .ruby-version\r\n\u001b[1m\u001b[32m      create\u001b[0m  config.ru\r\n\u001b[1m\u001b[32m      create\u001b[0m  .gitignore\r\n\u001b[1m\u001b[31m    conflict\u001b[0m  Gemfile\r\nOverwrite /home/vagrant/sample-rails/Gemfile? (enter \"h\" for help) [Ynaqdhm] ",
    "stdout_lines": [
        "\u001b[1m\u001b[34m       exist\u001b[0m  ",
        "\u001b[1m\u001b[32m      create\u001b[0m  README.md",
        "\u001b[1m\u001b[32m      create\u001b[0m  Rakefile",
        "\u001b[1m\u001b[32m      create\u001b[0m  .ruby-version",
        "\u001b[1m\u001b[32m      create\u001b[0m  config.ru",
        "\u001b[1m\u001b[32m      create\u001b[0m  .gitignore",
        "\u001b[1m\u001b[31m    conflict\u001b[0m  Gemfile",
        "Overwrite /home/vagrant/sample-rails/Gemfile? (enter \"h\" for help) [Ynaqdhm] "
    ]
}

サーバーにログインして、rails newして時間を測ったところ、だいたい7分ほど時間がかかることがわかった。
そこで、タイムアウト設定(timeout)を20分(1,200秒)に変更した。

[Tasks]

- name: Rails new
  expect:
    command: "bundle exec rails new ."
    responses:
      (.*)Overwrite (.*)Gemfile(.*): "Y"
    timeout: 1200

そうすると、タイムアウトせずに完了できた。

なお、タイムアウト設定を外したい場合は、 timeout: null と記載する。
ただし、コマンドプロンプトの入力待ち状態で止まってしまうと、インストールに時間がかかっているのか、入力待ち状態が延々続いていのか判別できなくなってしまうため、要注意。サーバーが入力待ちで止まっているのかかどうかは、デバッグモードの $ ansible-playbook -i hosts site.yml -vvv でも確認ができない。

Ansible Playbookで実行するとタスクが途中で止まる

Ansible Playbookのタスクが途中で止まってしまい(フリーズ、ハングアップ)、そこから先に進んでくれない。
たとえば以下のような状態で先に進まない。

$ ansible-playbook -i hosts site.yml --tags rails -vvv

・・・

TASK [rails : Rails new] **************************************************************************************************
task path: /Users/user/Documents/Programming/Servers/vagrant-ansible-ror/roles/rails/tasks/main.yml:42
<192.168.33.10> ESTABLISH SSH CONNECTION FOR USER: vagrant
<192.168.33.10> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o 'IdentityFile=".vagrant/machines/default/virtualbox/private_key"' -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o 'User="vagrant"' -o ConnectTimeout=10 -o ControlPath=/Users/user/.ansible/cp/d986014952 192.168.33.10 '/bin/sh -c '"'"'echo ~vagrant && sleep 0'"'"''
<192.168.33.10> (0, b'/home/vagrant\n', b'')
<192.168.33.10> ESTABLISH SSH CONNECTION FOR USER: vagrant
<192.168.33.10> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o 'IdentityFile=".vagrant/machines/default/virtualbox/private_key"' -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o 'User="vagrant"' -o ConnectTimeout=10 -o ControlPath=/Users/user/.ansible/cp/d986014952 192.168.33.10 '/bin/sh -c '"'"'( umask 77 && mkdir -p "` echo /home/vagrant/.ansible/tmp/ansible-tmp-1582382578.259243-102715982581542 `" && echo ansible-tmp-1582382578.259243-102715982581542="` echo /home/vagrant/.ansible/tmp/ansible-tmp-1582382578.259243-102715982581542 `" ) && sleep 0'"'"''
<192.168.33.10> (0, b'ansible-tmp-1582382578.259243-102715982581542=/home/vagrant/.ansible/tmp/ansible-tmp-1582382578.259243-102715982581542\n', b'')
Using module file /usr/local/Cellar/ansible/2.9.3/libexec/lib/python3.8/site-packages/ansible/modules/commands/command.py
<192.168.33.10> PUT /Users/user/.ansible/tmp/ansible-local-40504rzv7iwmj/tmpggurzqpy TO /home/vagrant/.ansible/tmp/ansible-tmp-1582382578.259243-102715982581542/AnsiballZ_command.py
<192.168.33.10> SSH: EXEC sftp -b - -C -o ControlMaster=auto -o ControlPersist=60s -o 'IdentityFile=".vagrant/machines/default/virtualbox/private_key"' -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o 'User="vagrant"' -o ConnectTimeout=10 -o ControlPath=/Users/user/.ansible/cp/d986014952 '[192.168.33.10]'
<192.168.33.10> (0, b'sftp> put /Users/user/.ansible/tmp/ansible-local-40504rzv7iwmj/tmpggurzqpy /home/vagrant/.ansible/tmp/ansible-tmp-1582382578.259243-102715982581542/AnsiballZ_command.py\n', b'')
<192.168.33.10> ESTABLISH SSH CONNECTION FOR USER: vagrant
<192.168.33.10> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o 'IdentityFile=".vagrant/machines/default/virtualbox/private_key"' -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o 'User="vagrant"' -o ConnectTimeout=10 -o ControlPath=/Users/user/.ansible/cp/d986014952 192.168.33.10 '/bin/sh -c '"'"'chmod u+x /home/vagrant/.ansible/tmp/ansible-tmp-1582382578.259243-102715982581542/ /home/vagrant/.ansible/tmp/ansible-tmp-1582382578.259243-102715982581542/AnsiballZ_command.py && sleep 0'"'"''
<192.168.33.10> (0, b'', b'')
<192.168.33.10> ESTABLISH SSH CONNECTION FOR USER: vagrant
<192.168.33.10> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o 'IdentityFile=".vagrant/machines/default/virtualbox/private_key"' -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o 'User="vagrant"' -o ConnectTimeout=10 -o ControlPath=/Users/user/.ansible/cp/d986014952 -tt 192.168.33.10 '/bin/sh -c '"'"'/usr/libexec/platform-python /home/vagrant/.ansible/tmp/ansible-tmp-1582382578.259243-102715982581542/AnsiballZ_command.py && sleep 0'"'"''

今回のケースでは、途中で止まっていた原因は、プロンプト側で質問されていて、その入力待ちになっているため。

$ vagrant ssh して、どのような質問をされているのか確認する。
今回は $ rails new するタスクだったので、それを実行。

$ vagrant ssh
[vagrant@localhost sample-rails]$ cd sample-rails
[vagrant@localhost sample-rails]$ bundle exec rails new .
       exist
   identical  README.md
   identical  Rakefile
   identical  .ruby-version
   identical  config.ru
   identical  .gitignore
    conflict  Gemfile
Overwrite /home/vagrant/sample-rails/Gemfile? (enter "h" for help) [Ynaqdhm]

「上書きしますか?」という質問で止まっていたことが判明。

Ansibleの expect を利用して入力実行するか、 Conditionals のwhenを利用してスキップすることで対応可能。

Vagrant x AnsibleでSSH接続エラー(WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!)

Vagrant 2.2.6 x ansible 2.9.3でPlaybook実行すると、SSHが拒否されてしまう。Vagrantの最新バージョンはキーを差し替えてしまうらしく、それが原因のようだった。

詳細:Vagrant 1.7+でSSH接続エラーが出た場合の対処法

対策は、以下2点で解決した。

1.hostsファイルにキーのパスを追記
ansible_ssh_private_key_file=.vagrant/machines/default/virtualbox/private_key ansible_ssh_user=vagrant

[hosts]

[vagrantservers]
192.168.33.10 ansible_ssh_private_key_file=.vagrant/machines/default/virtualbox/private_key ansible_ssh_user=vagrant

2.キーの再生成
$ ssh-keygen -R <対象のIP>

$ ssh-keygen -R 192.168.33.10

(参考)コマンド実行履歴

以下はすべてMac上で実行(Vagrantで立てたVMにはログインしていない)。

$ vagrant up
$ ansible-playbook -i hosts site.yml --check

PLAYBOOK: site.yml **********************************************************************************************************
1 plays in site.yml

PLAY [Setup Ruby] ***********************************************************************************************************

TASK [Gathering Facts] ******************************************************************************************************
task path: /Users/user/Documents/Programming/Servers/vagrant-ansible-ror/site.yml:2
<192.168.33.10> ESTABLISH SSH CONNECTION FOR USER: vagrant
<192.168.33.10> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o 'IdentityFile=".vagrant/machines/default/virtualbox/private_key"' -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o 'User="vagrant"' -o ConnectTimeout=10 -o ControlPath=/Users/user/.ansible/cp/d986014952 192.168.33.10 '/bin/sh -c '"'"'echo ~vagrant && sleep 0'"'"''
<192.168.33.10> (255, b'', b'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\r\n@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @\r\n@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\r\nIT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!\r\nSomeone could be eavesdropping on you right now (man-in-the-middle attack)!\r\nIt is also possible that a host key has just been changed.\r\nThe fingerprint for the ECDSA key sent by the remote host is\nSHA256:7VylyuI+cDZoFK8e16G93SKbEeRWEdVfWSpxyZylnHA.\r\nPlease contact your system administrator.\r\nAdd correct host key in /Users/user/.ssh/known_hosts to get rid of this message.\r\nOffending ECDSA key in /Users/user/.ssh/known_hosts:19\r\nECDSA host key for 192.168.33.10 has changed and you have requested strict checking.\r\nHost key verification failed.\r\n')
fatal: [192.168.33.10]: UNREACHABLE! => {
    "changed": false,
    "msg": "Failed to connect to the host via ssh: @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\r\n@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @\r\n@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\r\nIT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!\r\nSomeone could be eavesdropping on you right now (man-in-the-middle attack)!\r\nIt is also possible that a host key has just been changed.\r\nThe fingerprint for the ECDSA key sent by the remote host is\nSHA256:7VylyuI+cDZoFK8e16G93SKbEeRWEdVfWSpxyZylnHA.\r\nPlease contact your system administrator.\r\nAdd correct host key in /Users/user/.ssh/known_hosts to get rid of this message.\r\nOffending ECDSA key in /Users/user/.ssh/known_hosts:19\r\nECDSA host key for 192.168.33.10 has changed and you have requested strict checking.\r\nHost key verification failed.",
    "unreachable": true
}

PLAY RECAP ******************************************************************************************************************
192.168.33.10              : ok=0    changed=0    unreachable=1    failed=0    skipped=0    rescued=0    ignored=0



$ ll .vagrant/machines/default/virtualbox/
total 72
-rw-r--r--  1 user  staff    40B  2 18 00:08 action_provision
-rw-r--r--  1 user  staff    10B  2 18 00:41 action_set_name
-rw-r--r--  1 user  staff   122B  2 18 00:08 box_meta
-rw-r--r--  1 user  staff     3B  2 18 00:08 creator_uid
-rw-r--r--  1 user  staff    36B  2 18 00:08 id
-rw-r--r--  1 user  staff    32B  2 18 00:08 index_uuid
-rw-------  1 user  staff   1.6K  2 18 00:08 private_key
-rw-r--r--  1 user  staff   213B  2 18 00:42 synced_folders
-rw-r--r--  1 user  staff    63B  2 18 00:07 vagrant_cwd



$ ssh-keygen -R 192.168.33.10
# Host 192.168.33.10 found: line 19
/Users/user/.ssh/known_hosts updated.
Original contents retained as /Users/user/.ssh/known_hosts.old



$ vi hosts
$ cat hosts

[vagrantservers]
192.168.33.10 ansible_ssh_private_key_file=.vagrant/machines/default/virtualbox/private_key ansible_ssh_user=vagrant



$ ansible-playbook -i hosts site.yml --check

PLAYBOOK: site.yml **********************************************************************************************************
1 plays in site.yml

・・・

TASK [Gathering Facts] ****************************************************************************************************
The authenticity of host '192.168.33.10 (192.168.33.10)' can't be established.
ECDSA key fingerprint is SHA256:gVJMtxLjJDeWgKELM067s/AzdP3KO+Zwkigy9HuLfSQ.
Are you sure you want to continue connecting (yes/no)? yes

・・・

PLAY RECAP ******************************************************************************************************************
192.168.33.10              : ok=6    changed=0    unreachable=0    failed=0    skipped=4    rescued=0    ignored=0

参考

Mac x VagrantでVirtualBoxを起動すると音声出力がおかしくなる

Mac(macOS Catalina)でVagrant($ vagrant up)してVirtualBoxを起動すると、鳴らしていた音楽がこもったようなおかしい音になってしまう。

暫定対策

お手軽対策としては、VirtualBoxのオーディオ設定を一旦変更すると直る。

STEP1

対象のVirtualBoxを選択して「設定」>「オーディオ」を開き、「オーディオ出力を有効化」にチェックを入れて、「OK」を押す。

STEP2

再度、「設定」>「オーディオ」を開き、「オーディオ出力を有効化」のチェックを外して、「OK」を押す。

恒久対策

Vagrantfileに以下のオーディオを無効化する設定を記述する。

Vagrant.configure("2") do |config|
  config.vm.provider "virtualbox" do |vb|
    vb.customize ["modifyvm", :id, "--audio", "none"]
  end
end

全体像を見たい場合は以下参照。ファイル記述箇所。

[Vagrantfile]

# -*- mode: ruby -*-
# vi: set ft=ruby :

# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure("2") do |config|
  # The most common configuration options are documented and commented below.
  # For a complete reference, please see the online documentation at
  # https://docs.vagrantup.com.

  # Every Vagrant development environment requires a box. You can search for
  # boxes at https://vagrantcloud.com/search.
  config.vm.box = "centos/8"

  # Disable automatic box update checking. If you disable this, then
  # boxes will only be checked for updates when the user runs
  # `vagrant box outdated`. This is not recommended.
  # config.vm.box_check_update = false

  # Create a forwarded port mapping which allows access to a specific port
  # within the machine from a port on the host machine. In the example below,
  # accessing "localhost:8080" will access port 80 on the guest machine.
  # NOTE: This will enable public access to the opened port
  # config.vm.network "forwarded_port", guest: 80, host: 8080

  # Create a forwarded port mapping which allows access to a specific port
  # within the machine from a port on the host machine and only allow access
  # via 127.0.0.1 to disable public access
  # config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"

  # Create a private network, which allows host-only access to the machine
  # using a specific IP.
  config.vm.network "private_network", ip: "192.168.33.10"

  # Create a public network, which generally matched to bridged network.
  # Bridged networks make the machine appear as another physical device on
  # your network.
  # config.vm.network "public_network"

  # Share an additional folder to the guest VM. The first argument is
  # the path on the host to the actual folder. The second argument is
  # the path on the guest to mount the folder. And the optional third
  # argument is a set of non-required options.
  # config.vm.synced_folder "../data", "/vagrant_data"

  # begin disable audio
  config.vm.provider "virtualbox" do |vb|
    vb.customize ["modifyvm", :id, "--audio", "none"]
  end
  # end disable audio

  # Provider-specific configuration so you can fine-tune various
  # backing providers for Vagrant. These expose provider-specific options.
  # Example for VirtualBox:
  #
  config.vm.provider "virtualbox" do |vb|
  #   # Display the VirtualBox GUI when booting the machine
  #   vb.gui = true
  #
  #   # Customize the amount of memory on the VM:
  #   vb.memory = "1024"
    vb.memory = "2048"
    vb.name = "centos_ror"
  end
  #
  # View the documentation for the provider you are using for more
  # information on available options.

  # Enable provisioning with a shell script. Additional provisioners such as
  # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the
  # documentation for more information about their specific syntax and use.
  # config.vm.provision "shell", inline: <<-SHELL
  #   apt-get update
  #   apt-get install -y apache2
  # SHELL
  config.vm.provision "ansible" do |ansible|
    ansible.playbook = "provisioning/site.yml"
    ansible.inventory_path = "provisioning/hosts"
    ansible.limit = 'all'
    ansible.raw_arguments = ['--check']
  end
end

Ansible x Vagrant構築メモ

さくらのナレッジ - AnsibleとVagrantで開発環境を構築する をもとに軽くテスト的にMacで構築したときのメモ。
昔の記事なので少しだけうまくいかない箇所があるため、その補完用にメモ。

構築方法

さくらのナレッジ - AnsibleとVagrantで開発環境を構築する の大項目の中でハマった箇所のみ補完して以降に記載。

Vagrantfileの作成

config.vm.boxの名称は、 Discover Vagrant Boxes で検索して取得する。ちなみに、 [作成者]/[Box名] という命名規則になっている。
「bento」は「chef」が提供していて安心感があるため、今回はそれを利用。

[Vagrantfile]

VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "bento/debian-10"

  config.vm.network "private_network", ip: "192.168.33.10"

  config.vm.provision "ansible" do |ansible|
    ansible.playbook = "provisioning/site.yml"
    ansible.inventory_path = "provisioning/hosts"
    ansible.limit = 'all'
  end
end

provisioning/site.ymlの作成

さくらのナレッジ記事のとおりにやると、「sudo: true」の箇所でエラーが表示される。おそらくいまは実行できない設定と思われる。

$ vagrant provision
==> default: [vagrant-hostsupdater] Checking for host entries
==> default: Running provisioner: ansible...
Vagrant has automatically selected the compatibility mode '2.0'
according to the Ansible version installed (2.9.3).

Alternatively, the compatibility mode can be specified in your Vagrantfile:
https://www.vagrantup.com/docs/provisioning/ansible_common.html#compatibility_mode

    default: Running ansible-playbook...
ERROR! 'sudo' is not a valid attribute for a Play

The error appears to be in '/Users/user/Desktop/tmp/ansible_vagrant/provisioning/site.yml': line 2, column 3, but may
be elsewhere in the file depending on the exact syntax problem.

The offending line appears to be:

---
- hosts: vagrants
  ^ here

Ansible failed to complete successfully. Any error output should be
visible above. Please fix these errors and try again.

sudoユーザーとして実行しないとパッケージのインストールなどができないため、設定自体は必要になる。そこで「become: yes」の設定に書き換えると通るようになる。

[Vagrantfile]

---
- hosts: vagrants
  become: yes
  user: vagrant
  tasks:
    - name: install packages zsh
      apt: name=zsh update_cache=yes

vagrant up

$ vagrant provision を実行すると、いままでの設定でうまくいっていることがわかる。もしエラーだった場合は、 failed=1 のように表示される。

補足:teratail - vagrant provisionのコマンドについて(プロビジョニングの実行タイミング)

$ vagrant provision
==> default: [vagrant-hostsupdater] Checking for host entries
==> default: Running provisioner: ansible...
Vagrant has automatically selected the compatibility mode '2.0'
according to the Ansible version installed (2.9.3).

Alternatively, the compatibility mode can be specified in your Vagrantfile:
https://www.vagrantup.com/docs/provisioning/ansible_common.html#compatibility_mode

    default: Running ansible-playbook...

PLAY [vagrants] ****************************************************************

TASK [Gathering Facts] *********************************************************
[WARNING]: Platform linux on host 192.168.33.10 is using the discovered Python
interpreter at /usr/bin/python, but future installation of another Python
interpreter could change this. See https://docs.ansible.com/ansible/2.9/referen
ce_appendices/interpreter_discovery.html for more information.

ok: [192.168.33.10]

TASK [install packages zsh] ****************************************************
ok: [192.168.33.10]

PLAY RECAP *********************************************************************
192.168.33.10              : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

rbenvとRubyのインストール

さくら記事だと、provisioning/site.ymlに記載されているRubyのバージョンが古くてサポート外になっているのか、エラーが表示される。(JSON部分は整形済み)

$ vagrant provision

・・・

TASK [install ruby 2.1.5] ******************************************************
fatal: [192.168.33.10]: FAILED! => {
    "changed": true,
    "cmd": "export RBENV_ROOT=/home/vagrant/.rbenv; export PATH=$RBENV_ROOT/bin:$PATH; echo N | rbenv install 2.1.5; rbenv global 2.1.5",
    "delta": "0:02:34.188692",
    "end": "2020-02-09 06:14:57.507708",
    "msg": "non-zero return code",
    "rc": 1,
    "start": "2020-02-09 06:12:23.319016",
    "stderr": "Downloading ruby-2.1.5.tar.bz2...\n-> https://cache.ruby-lang.org/pub/ruby/2.1/ruby-2.1.5.tar.bz2\nInstalling ruby-2.1.5...\n\nWARNING: ruby-2.1.5 is past its end of life and is now unsupported.\nIt no longer receives bug fixes or critical security updates.\n\n\nBUILD FAILED (Debian 10 using ruby-build 20200115-8-g73b926b)\n\nInspect or clean up the working tree at /tmp/ruby-build.20200209061223.14454.8rtP6p\nResults logged to /tmp/ruby-build.20200209061223.14454.log\n\nLast 10 log lines:\n ^\nossl_pkey_dsa.c: In function ‘ossl_dsa_is_public’:\nossl_pkey_dsa.c:273:1: warning: control reaches end of non-void function [-Wreturn-type]\n }\n ^\nmake[2]: *** [Makefile:281: ossl_pkey_dsa.o] Error 1\nmake[2]: Leaving directory '/tmp/ruby-build.20200209061223.14454.8rtP6p/ruby-2.1.5/ext/openssl'\nmake[1]: *** [exts.mk:191: ext/openssl/all] Error 2\nmake[1]: Leaving directory '/tmp/ruby-build.20200209061223.14454.8rtP6p/ruby-2.1.5'\nmake: *** [uncommon.mk:180: build-ext] Error 2\nrbenv: version `2.1.5' not installed",
    "stderr_lines": [
        "Downloading ruby-2.1.5.tar.bz2...",
        "-> https://cache.ruby-lang.org/pub/ruby/2.1/ruby-2.1.5.tar.bz2",
        "Installing ruby-2.1.5...",
        "",
        "WARNING: ruby-2.1.5 is past its end of life and is now unsupported.",
        "It no longer receives bug fixes or critical security updates.",
        "",
        "",
        "BUILD FAILED (Debian 10 using ruby-build 20200115-8-g73b926b)",
        "",
        "Inspect or clean up the working tree at /tmp/ruby-build.20200209061223.14454.8rtP6p",
        "Results logged to /tmp/ruby-build.20200209061223.14454.log",
        "",
        "Last 10 log lines:",
        " ^",
        "ossl_pkey_dsa.c: In function ‘ossl_dsa_is_public’:",
        "ossl_pkey_dsa.c:273:1: warning: control reaches end of non-void function [-Wreturn-type]",
        " }",
        " ^",
        "make[2]: *** [Makefile:281: ossl_pkey_dsa.o] Error 1",
        "make[2]: Leaving directory '/tmp/ruby-build.20200209061223.14454.8rtP6p/ruby-2.1.5/ext/openssl'",
        "make[1]: *** [exts.mk:191: ext/openssl/all] Error 2",
        "make[1]: Leaving directory '/tmp/ruby-build.20200209061223.14454.8rtP6p/ruby-2.1.5'",
        "make: *** [uncommon.mk:180: build-ext] Error 2",
        "rbenv: version `2.1.5' not installed"
    ],
    "stdout": "",
    "stdout_lines": []
}

PLAY RECAP *********************************************************************
192.168.33.10              : ok=25   changed=18   unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

Ansible failed to complete successfully. Any error output should be
visible above. Please fix these errors and try again.

Ruby公式サイト より、Rubyの最新バージョンを確認して、そのバージョンに書き換えたら通った。

[provisioning/site.yml]

- hosts: vagrants
  become: yes
  user: vagrant
  vars:
    vagrant_home: "/home/vagrant" 
  tasks:
    - name: install packages build-essential
      apt: name=build-essential update_cache=yes

    - name: install packages git  
      apt: name=git update_cache=yes

    - name: install packages git-core
      apt: name=git-core update_cache=yes

    - name: install packages libssl-dev
      apt: name=libssl-dev update_cache=yes

    - name: install packages libqt4-dev
      apt: name=libqt4-dev update_cache=yes

    - name: install packages libc6-dev
      apt: name=libc6-dev update_cache=yes

    - name: install packages automake
      apt: name=automake update_cache=yes

    - name: install packages libtool
      apt: name=libtool update_cache=yes

    - name: install packages libyaml-dev
      apt: name=libyaml-dev update_cache=yes

    - name: install packages zlib1g
      apt: name=zlib1g update_cache=yes

    - name: install packages zlib1g-dev
      apt: name=zlib1g-dev update_cache=yes

    - name: install packages openssl
      apt: name=openssl update_cache=yes

    - name: install packages libssl-dev
      apt: name=libssl-dev update_cache=yes

    - name: install packages libreadline-dev
      apt: name=libreadline-dev update_cache=yes

    - name: install packages libxml2-dev
      apt: name=libxml2-dev update_cache=yes

    - name: install packages libxslt1-dev
      apt: name=libxslt1-dev update_cache=yes

    - name: install packages libncurses5-dev
      apt: name=libncurses5-dev update_cache=yes

    - name: install packages pkg-config
      apt: name=pkg-config update_cache=yes

    - name: install packages chrpath
      apt: name=chrpath update_cache=yes

    - name: install packages libfontconfig1-dev
      apt: name=libfontconfig1-dev update_cache=yes

    - name: install packages libxft-dev
      apt: name=libxft-dev update_cache=yes

    - name: install rbenv
      git: repo=https://github.com/sstephenson/rbenv.git
           dest={{ vagrant_home }}/.rbenv
           version=master

    - name: add rbenv path to bash_profile
      copy: src=files/rbenv.sh dest=/etc/profile.d/rbenv.sh
      # copy: content="export PATH=\"/home/vagrant/.rbenv/bin:$PATH\"\neval \"$(rbenv init -)\"" dest=/etc/profile.d/rbenv.sh

    - name: install ruby_build
      git: repo=https://github.com/sstephenson/ruby-build.git
           dest={{ vagrant_home }}/.rbenv/plugins/ruby-build
           version=master

    - name: install ruby 2.7.0
      shell: "export RBENV_ROOT={{ vagrant_home }}/.rbenv; export PATH=$RBENV_ROOT/bin:$PATH; echo N | rbenv install 2.7.0; rbenv global 2.7.0"
      args:
        creates: "{{ vagrant_home }}/.rbenv/versions/2.7.0/"

    - name: install bundler
      shell: "{{ vagrant_home }}/.rbenv/shims/gem install bundler"
      args:
        creates: "{{ vagrant_home }}/.rbenv/shims/bundle"

    - name: change ~/.rbenv owner to vagrant
      file: path={{ vagrant_home }}/.rbenv state=directory owner=vagrant group=vagrant recurse=yes

設定したら反映。

$ vagrant provision

・・・

PLAY RECAP *********************************************************************
192.168.33.10              : ok=28   changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

$ vagrant ssh
Linux debian-10 4.19.0-6-amd64 #1 SMP Debian 4.19.67-2+deb10u2 (2019-11-11) x86_64

This system is built by the Bento project by Chef Software
More information can be found at https://github.com/chef/bento

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sun Feb  9 11:16:28 2020 from 10.0.2.2

vagrant@debian-10:~$ ruby -v
ruby 2.7.0p0 (2019-12-25 revision 647ee6f091) [x86_64-linux]

参考サイト

macOS CatalinaでVagrant x CentOS8 x Railsの構築

つまりCentOS8でRails環境を構築するだけなのだが、ハマったのでメモ。

構築方法

ここに書かれている内容がわかりやく具体的でスムーズに進められるため、大筋はこの手順どおりとなる。(こちらの記事のおかげで本当に助かりました。素晴らしい記事です。)

Qiita - Ruby on Railsの開発環境をVagrantで構築する

しかし、PostgreSQLのバージョンが古いためにインストールができなかったり、Rails構築前にインストールしないといけないもの(Yarnなど)があるため、その部分を補完していく。

補完箇所

Qiita記事の大項目にあわせて補完箇所を以降に記載。

Vagrantのセットアップ

Qiita記事を参考に書き換えたところ、Vagrantfile(設定ファイル)は以下のようになった。(CentOSのバージョンだけは自分の環境にあわせて変更)

# -*- mode: ruby -*-
# vi: set ft=ruby :

# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure("2") do |config|
  # The most common configuration options are documented and commented below.
  # For a complete reference, please see the online documentation at
  # https://docs.vagrantup.com.

  # Every Vagrant development environment requires a box. You can search for
  # boxes at https://vagrantcloud.com/search.
  #config.vm.box = "base"
  config.vm.box = "centos/8"

  # Disable automatic box update checking. If you disable this, then
  # boxes will only be checked for updates when the user runs
  # `vagrant box outdated`. This is not recommended.
  # config.vm.box_check_update = false

  # Create a forwarded port mapping which allows access to a specific port
  # within the machine from a port on the host machine. In the example below,
  # accessing "localhost:8080" will access port 80 on the guest machine.
  # NOTE: This will enable public access to the opened port
  config.vm.network "forwarded_port", guest: 2000, host: 3000

  # Create a forwarded port mapping which allows access to a specific port
  # within the machine from a port on the host machine and only allow access
  # via 127.0.0.1 to disable public access
  # config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"

  # Create a private network, which allows host-only access to the machine
  # using a specific IP.
  # config.vm.network "private_network", ip: "192.168.33.10"

  # Create a public network, which generally matched to bridged network.
  # Bridged networks make the machine appear as another physical device on
  # your network.
  # config.vm.network "public_network"

  # Share an additional folder to the guest VM. The first argument is
  # the path on the host to the actual folder. The second argument is
  # the path on the guest to mount the folder. And the optional third
  # argument is a set of non-required options.
  # config.vm.synced_folder "../data", "/vagrant_data"

  # Provider-specific configuration so you can fine-tune various
  # backing providers for Vagrant. These expose provider-specific options.
  # Example for VirtualBox:
  #
  config.vm.provider "virtualbox" do |vb|
  #   # Display the VirtualBox GUI when booting the machine
  #   vb.gui = true
  #
  #   # Customize the amount of memory on the VM:
     vb.memory = "2048"
     vb.name = "centos8"
  end
  #
  # View the documentation for the provider you are using for more
  # information on available options.

  # Enable provisioning with a shell script. Additional provisioners such as
  # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the
  # documentation for more information about their specific syntax and use.
  # config.vm.provision "shell", inline: <<-SHELL
  #   apt-get update
  #   apt-get install -y apache2
  # SHELL
end

Rubyのインストール

Qiita記事は以下のようになっているが

$ rbenv install 2.3.1
$ rbenv global 2.3.1
$ gem install bundler

実行するとmakeできないと言われる。(バージョンはRubyの現時点の最新バージョンにして実行)

$ rbenv install 2.7.0
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
    LANGUAGE = (unset),
    LC_ALL = (unset),
    LANG = "ja_JP.UTF-8"
    are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").
Downloading ruby-2.7.0.tar.bz2...
-> https://cache.ruby-lang.org/pub/ruby/2.7/ruby-2.7.0.tar.bz2
Installing ruby-2.7.0...

BUILD FAILED (CentOS Linux 8 using ruby-build 20200115-8-g73b926b)

Inspect or clean up the working tree at /tmp/ruby-build.20200208022103.10752.rpki8m
Results logged to /tmp/ruby-build.20200208022103.10752.log

Last 10 log lines:
checking for _setjmp as a macro or function... yes
checking for sigsetjmp as a macro or function... no
checking for setjmp type... __builtin_setjmp
checking for prefix of external symbols... NONE
checking pthread.h usability... yes
checking pthread.h presence... yes
checking for pthread.h... yes
checking if make is GNU make... ./configure: line 29860: make: command not found
no
checking for safe null command for make... configure: error: no candidate for safe null command

代わりに以下を実行する。

makeをインストールする。

$ sudo yum install -y make

最新バージョンを確認する。

$ rbenv install --list

自分の場合は2.7.0が最新バージョンだっため、それを指定して実行する。

$ rbenv install 2.7.0
$ rbenv global 2.7.0
$ gem install bundler

PostgreSQLのインストール

Qiita記事は以下のようになっているが

$ sudo rpm -ivh http://yum.postgresql.org/9.3/redhat/rhel-6-x86_64/pgdg-centos93-9.3-1.noarch.rpm
$ sudo yum -y install postgresql93-server postgresql-devel postgresql93-contrib

以下のようなエラーが表示される。バージョンが古く、メンテナンス切れでリンクがなくなっていることが原因。

$ sudo rpm -ivh http://yum.postgresql.org/9.3/redhat/rhel-6-x86_64/pgdg-centos93-9.3-1.noarch.rpm
Retrieving http://yum.postgresql.org/9.3/redhat/rhel-6-x86_64/pgdg-centos93-9.3-1.noarch.rpm
curl: (22) The requested URL returned error: 403
error: skipping http://yum.postgresql.org/9.3/redhat/rhel-6-x86_64/pgdg-centos93-9.3-1.noarch.rpm - transfer failed

代わりに以下を実行する。

PostgreSQL公式サイトのDownloadから、最新版とPlatformを指定し、そこで表示されるコマンドをsudoで実行する。

PostgreSQL - Linux downloads (Red Hat family) Red Hat

$ sudo yum install https://download.postgresql.org/pub/repos/yum/reporpms/EL-6-x86_64/pgdg-redhat-repo-latest.noarch.rpm
$ sudo yum install -y postgresql12
$ sudo yum install -y postgresql12-server

そして以下を実行する。postgresql12-contrib の部分は、上記で表示されるバージョンにあわせて書き換えること。

$ sudo yum install -y postgresql-devel
$ sudo yum install -y postgresql12-contrib

以降はQiitaの記事のとおりに実行していく。ただし、バージョンの書き換えを忘れないように。

Railsプロジェクトの作成

Qiita記事を実行する前に Yarn Installation に沿ってYarnをインストールする。

$ curl --silent --location https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /etc/yum.repos.d/yarn.repo
$ sudo yum install -y yarn

Qiita記事内では特に利用はされていないが、ついでにSqliteもインストールしておく。

$ sudo yum install sqlite-devel

Qiita記事では以下のようにホームディレクトリにGemファイル郡を保存するように指定されているが、--pathフラグは今後なくなる旨の警告が表示される。

$ bundle install --path ~/bundler/hello_app/vendor/bundle
[DEPRECATED] The `--path` flag is deprecated because it relies on being remembered across bundler invocations, which bundler will no longer do in future versions. Instead please use `bundle config set path 'vendor/bundle'`, and stop using this flag

警告に表示されたコマンドに従って、パスを設定ファイルに書き込む。ちなみに、Railsプロジェクトのルート配下にvendorフォルダを作るやり方が個人的にオススメのため、vendor/bundleとして実行する。

$ bundle config set path 'vendor/bundle'
Your application has set path to "vendor/bundle". This will override the global value you are currently setting

エラーメモ

pg_config... no

もし、PostgreSQLがインストールされていない旨のエラーが表示され、さらに gem install pg してもエラーが表示される場合は、、、

$ bundle exec rails new . --database=postgresql --skip-spring
       exist
      create  README.md
      create  Rakefile
      create  .ruby-version

・・・

Installing pg 1.2.2 with native extensions
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

    current directory: /home/vagrant/rails-workspace/hello_app/vendor/bundle/ruby/2.7.0/gems/pg-1.2.2/ext
/home/vagrant/.rbenv/versions/2.7.0/bin/ruby -I /home/vagrant/.rbenv/versions/2.7.0/lib/ruby/2.7.0 -r
./siteconf20200208-30318-1ercdmi.rb extconf.rb
checking for pg_config... no
No pg_config... trying anyway. If building fails, please try again with
 --with-pg-config=/path/to/pg_config
checking for libpq-fe.h... no
Can't find the 'libpq-fe.h header
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers.  Check the mkmf.log file for more details.  You may
need configuration options.

・・・

To see why this extension failed to compile, please check the mkmf.log which can be found here:

  /home/vagrant/rails-workspace/hello_app/vendor/bundle/ruby/2.7.0/extensions/x86_64-linux/2.7.0/pg-1.2.2/mkmf.log

extconf failed, exit code 1

Gem files will remain installed in /home/vagrant/rails-workspace/hello_app/vendor/bundle/ruby/2.7.0/gems/pg-1.2.2 for
inspection.
Results logged to
/home/vagrant/rails-workspace/hello_app/vendor/bundle/ruby/2.7.0/extensions/x86_64-linux/2.7.0/pg-1.2.2/gem_make.out

An error occurred while installing pg (1.2.2), and Bundler cannot continue.
Make sure that `gem install pg -v '1.2.2' --source 'https://rubygems.org/'` succeeds before bundling.

In Gemfile:
  pg
         run  bundle binstubs bundler
Could not find gem 'pg (>= 0.18, < 2.0)' in any of the gem sources listed in your Gemfile.
       rails  webpacker:install
Could not find gem 'pg (>= 0.18, < 2.0)' in any of the gem sources listed in your Gemfile.
Run `bundle install` to install missing gems.

・・・

$ gem install pg -v '1.2.2' --source 'https://rubygems.org/'
Fetching pg-1.2.2.gem
Building native extensions. This could take a while...
ERROR:  Error installing pg:
    ERROR: Failed to build gem native extension.

postgresql-develをインストールすると解決する。

$ sudo yum install postgresql-devel

Yarn not installed

Yarnがないと言われる場合は、、、

$ bundle exec rails new . --database=postgresql --skip-spring
       exist
      create  README.md
      create  Rakefile

・・・

Bundle complete! 15 Gemfile dependencies, 73 gems now installed.
Bundled gems are installed into `./vendor/bundle`
         run  bundle binstubs bundler
The dependency tzinfo-data (>= 0) will be unused by any of the platforms Bundler is installing for. Bundler is installing for ruby but the dependency is only for x86-mingw32, x86-mswin32, x64-mingw32, java. To add those platforms to the bundle, run `bundle lock --add-platform x86-mingw32 x86-mswin32 x64-mingw32 java`.
       rails  webpacker:install
Yarn not installed. Please download and install Yarn from https://yarnpkg.com/lang/en/docs/install/

Yarn Installation でCentOSを選択してYarnをインストールすると解決する。

$ curl --silent --location https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /etc/yum.repos.d/yarn.repo
$ sudo yum install -y yarn

sqlite3.h... no

Sqliteがないと言われる場合は、、、

$ mkdir hello_app
$ cd hello_app
$ bundle init
$ vi Gemfile ← 編集でコメントアウトされているrailsを外すだけ
$ bundle install
$ bundle exec rails new .
       exist
      create  README.md
      create  Rakefile

・・・

Fetching sqlite3 1.4.2
Installing sqlite3 1.4.2 with native extensions
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

    current directory: /home/vagrant/rails-workspace/hello_app/vendor/bundle/ruby/2.7.0/gems/sqlite3-1.4.2/ext/sqlite3
/home/vagrant/.rbenv/versions/2.7.0/bin/ruby -I /home/vagrant/.rbenv/versions/2.7.0/lib/ruby/2.7.0 -r
./siteconf20200208-12025-13ic82v.rb extconf.rb
checking for sqlite3.h... no
sqlite3.h is missing. Try 'brew install sqlite3',
'yum install sqlite-devel' or 'apt-get install libsqlite3-dev'
and check your shared library search path (the
location where your sqlite3 shared library is located).
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers.  Check the mkmf.log file for more details.  You may
need configuration options.

・・・

To see why this extension failed to compile, please check the mkmf.log which can be found here:

  /home/vagrant/rails-workspace/hello_app/vendor/bundle/ruby/2.7.0/extensions/x86_64-linux/2.7.0/sqlite3-1.4.2/mkmf.log

extconf failed, exit code 1

Gem files will remain installed in /home/vagrant/rails-workspace/hello_app/vendor/bundle/ruby/2.7.0/gems/sqlite3-1.4.2 for
inspection.
Results logged to
/home/vagrant/rails-workspace/hello_app/vendor/bundle/ruby/2.7.0/extensions/x86_64-linux/2.7.0/sqlite3-1.4.2/gem_make.out

An error occurred while installing sqlite3 (1.4.2), and Bundler cannot continue.
Make sure that `gem install sqlite3 -v '1.4.2' --source 'https://rubygems.org/'` succeeds before bundling.

In Gemfile:
  sqlite3
         run  bundle binstubs bundler
Could not find gem 'sqlite3 (~> 1.4)' in any of the gem sources listed in your Gemfile.
         run  bundle exec spring binstub --all
Could not find gem 'sqlite3 (~> 1.4)' in any of the gem sources listed in your Gemfile.
Run `bundle install` to install missing gems.
       rails  webpacker:install
Could not find gem 'sqlite3 (~> 1.4)' in any of the gem sources listed in your Gemfile.
Run `bundle install` to install missing gems.
[vagrant@localhost hello_app]$ gem install sqlite3 -v '1.4.2
> ç e
> exit
> ç^C

Sqliteをインストールすると解決する。

$ sudo yum install sqlite-devel

参考サイト