My Favorite Things - Coding or die.

とある技術者の経験記録、的な。

Vagrant + CentOS7 で、RustのWebフレームワークRocketを発射する

Linuxとか環境面詳しくないのでメモ。

Rocketは最近出たRustのWebフレームワーク。
https://rocket.rs

環境

VirtualBox: 5.0.30
Vagrant: 1.9.1
CentOS: 7.1
Rust: 1.16.0-nightly
Rocket: 0.1.2

ちなみにこれを書いている時点で最新のCentOSは7.3だったけれど、vagrant upで立ち上げたら途中で止まってしまったので断念。

VagrantでCentOS7を立ち上げる

まずは発射台を準備。

$ mkdir launch-pad
$ cd launch-pad

Boxイメージは、Chef社がOSSとして公開してる「Bento」を使う。
(弁当箱とは誰がうまいことを)
https://atlas.hashicorp.com/bento

$ vagrant init bento/centos-7.1
A `Vagrantfile` has been placed in this directory. You are now
ready to `vagrant up` your first virtual environment! Please read
the comments in the Vagrantfile as well as documentation on
`vagrantup.com` for more information on using Vagrant.

Vagrantfileは以下のようにしてプライベートネットワークとして接続できるようにしておく。

Vagrant.configure("2") do |config|
  config.vm.box = "bento/centos-7.1"
  config.vm.network "private_network", ip: "192.168.33.11", auto_config: false
end

原因はよく分かっていないのだけれど、auto_config: falseを設定しておかないと、立ち上げたVM上で正しくIPアドレスが振り当てられなかった。

VMイメージを起動。(Boxの取得から始まるので時間かかるよ!)

$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
...

SSHで接続。

$ vagrant ssh
-bash: warning: setlocale: LC_CTYPE: cannot change locale (UTF-8): No such file or directory
[vagrant@localhost ~]$

基本設定

ファイアウォールを切ってしまう。(仮想環境なので)

$ sudo systemctl stop firewalld
$ sudo systemctl disable firewalld

SELinuxが無効か確認。今回は無効になっているのでそのまま。

$ getenforce
Permissive

Rustのインストール

Rocketでは構文拡張を利用するため、NigthlyなRustが必須。(2016/12/30時点)

Rust1.14.0で公式ツールとなったrustupをインストールする。 https://rustup.rs

$ curl https://sh.rustup.rs -sSf | sh
info: downloading installer
...

選択肢が表示されるが、とりあえずデフォルトの1)を選択。

Current installation options:

   default host triple: x86_64-unknown-linux-gnu
     default toolchain: stable
  modify PATH variable: yes

1) Proceed with installation (default)
2) Customize installation
3) Cancel installation

Rust is installed now. Great!

To get started you need Cargo's bin directory in your PATH environment variable. Next time you log in this will be done automatically.

To configure your current shell run source $HOME/.cargo/env

パスを設定してくださいと言われるので、.bash_profile に記述しておく。

# Rust
source $HOME/.cargo/env

再読込して現在のシェルに反映させておく。これでRustが使えるようになった。

$ source ~/.bash_profile
$ rustc --version
rustc 1.14.0 (e8a012324 2016-12-16)

そしてRustを最新版(Nightly)に変更。

$ rustup default nightly
$ rustc --version
rustc 1.16.0-nightly (4ecc85beb 2016-12-28)

Hello, world

Rocket用のプロジェクトを作成して、そこに移動。

$ cargo new hello-rocket --bin
     Created binary (application) `hello-rocket` project
$ cd hello-rocket

Cargo.toml の依存ライブラリに以下を追加。

[dependencies]
rocket = "0.1.2"
rocket_codegen = "0.1.2"

src/main.rs を以下のように編集。このあたりは公式ドキュメントどおり。

#![feature(plugin)]
#![plugin(rocket_codegen)]

extern crate rocket;

#[get("/")]
fn index() -> &'static str {
    "Hello, world!"
}

fn main() {
    rocket::ignite().mount("/", routes![index]).launch();
}

そしてビルド・実行・・・するがエラーになる。

$ cargo run
...

error: aborting due to previous error

error: Could not compile `unicase`.

To learn more, run the command again with --verbose.

どうやらgccが入っていないのが原因らしいのでインストール。

$ sudo yum -y install gcc
...

今度こそロケットを打ち上げられた。

$ cargo run

Finished debug [unoptimized + debuginfo] target(s) in 79.19 secs
 Running `target/debug/hello-rocket`
🔧  Configured for development.
=> listening: localhost:8000
=> logging: Normal
🛰  Mounting '/':
=> GET /
🚀  Rocket has launched from http://localhost:8000...

VM内でcurlを叩くとちゃんと動いていることが分かる。

$ curl localhost:8000
Hello, world!

80ポートで起動する

ここからはあんまり正攻法じゃない。 ので、とりあえずこの方法でうまくいった程度の話。

Rocketのドキュメントを見ると、Productionで実行するには以下のようにすればよいと書いてある。

$ sudo ROCKET_ENV=staging cargo run
sudo: cargo: command not found

が、エラーとなる。

これは環境変数PATHがsudo時に引き継がれないのが問題らしい。

$ env | grep PATH
PATH=/home/vagrant/.cargo/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/vagrant/.local/bin:/home/vagrant/bin
$ sudo env | grep PATH
PATH=/sbin:/bin:/usr/sbin:/usr/bin

で、調べるといろいろと情報が出てくる。

CentOS で sudo 時に実行ユーザーのPATHを引き継ぐ http://qiita.com/ogwmtnr/items/3ec2fab50d069a3cf335

sudoで環境変数を引き継ぎたい http://mikio.github.io/article/2012/03/10_sudo.html

が、何を試しても一向にcargoのパスが引き継がれない。

仕方ないのでルートユーザーでもrustupを入れてしまう。(同様なので方法は割愛)

$ su -
# rustupのインストールと設定

ちなみにパスワードは「vagrant」。

そしてそのままルートユーザーで以下を実行すると、80ポートで起動する。

# ROCKET_ENV=staging cargo run

🔧  Configured for staging.
    => listening: 0.0.0.0:80
    => logging: Normal
🛰  Mounting '/':
    => GET /
🚀  Rocket has launched from http://0.0.0.0:80...

ホストマシンからブラウザでアクセスしてみるとちゃんと動いている。 http://192.168.33.13

GET /:
    => Matched: GET /
    => Outcome: Succcess
    => Response succeeded.
GET /favicon.ico:
    => Error: No matching routes for GET /favicon.ico.
    => Warning: Responding with 404 Not Found catcher.
    => Response succeeded.

ちなみにデフォルトの8000ポートだと以下のように指定してもアクセスできなかった。
http://192.168.33.13:8000/

ファイアウォールを切ったので問題ないと思ったのだが、何か設定がマズイのかもしれない。

終わり

Linuxとか環境構築とかあんまり経験ないので思ったよりもずっとしんどかった。 まぁしかしVagrantとか楽でいいなと思った。

とりあえず以下は解決したい課題。

  • ルートユーザで実行しちゃってる。(本番環境なら大問題)
  • 8000ポートでホストマシンから接続できるように。
  • Linuxとか詳しくなる。