一直关注 Rust 语言,最近一下发现了两个 web 框架,Iron 和 Nickel.rs。先不说这两个框架成熟度如何,一般情况下,一个语言有了 web 框架,算是一个里程碑,说明他离靠谱也不远了。这样我决定跟一下 nightly 版本(新框架都是跟 nightly),另外也能感受一下 Yehuda Katz 的构建工具 Cargo。ArchLinux 的仓库里已经有 0.11 版本,再用脚本安装必然会有冲突。于是想到了最近半年最火的 Docker,可以轻松的创建多个环境,正是一个非常好的场景。
安装
安装 Docker, Arch Linux 仓库里很早就有,非常方便:sudo pacman -S docker
。完成之后启动他:sudo systemctl start docker
。
之后我们拉一个 ubuntu 的镜像下来:docker pull ubuntu
。
完成之后,我们启动一个 container,做一些基本的 setup:docker run -i -t ubuntu:14.04 /bin/bash
这相当与运行在 ubuntu:14.04 这个镜像上运行一个 shell,接下来就进入了这个 shell 环境,和 ubuntu 安装版本完全一致,我们做一些基础的准备,安装一些必要的工具:apt-get install build-essentials git curl libssl-dev
之后,就可以下载 Rust 提供的脚本来安装 nightly 版本了:curl -s http://www.rust-lang.org/rustup.sh > rustup
这里有个问题,rustup 脚本判断64位系统时会出错导致安装失败:
# Detect 64 bit linux systems with 32 bit userland and force 32 bit compilation
if [ $CFG_OSTYPE = unknown-linux-gnu -a $CFG_CPUTYPE = x86_64 ]
then
file -L "$SHELL" | grep -q "x86[_-]64"
if [ $? != 0 ]; then
CFG_CPUTYPE=i686
fi
fi
因为在我的机器上已知系统是64位,就强行绕过了他的判断。
if [ $CFG_OSTYPE = unknown-linux-gnu -a $CFG_CPUTYPE = x86_64 ]
then
file -L "$SHELL" | grep -q "x86[_-]64"
if [ $? == 0 ]; then
CFG_CPUTYPE=i686
fi
fi
之后执行 rustup 就可以直接安装最近的 rustc 和 cargo 了。安装完成执行 rustc -v
和 cargo --version
(两个工具还不统一!)可以了解安装情况。
exit 退出 shell,commit 你的镜像,这样一个干净的镜像要好好保存:docker commit IMAGE_ID sunng/rust-nightly
Hello World
之后可以写点代码了,我们不在 docker 里写,我们在 host 机器上写,然后挂载到 docker 上,因此 emacs 什么的也不用配置了。
创建一个目录,比如在 $HOME/var/docker/helloworld
下,最简单的 rust 项目只要两个文件: Cargo.toml
和 src/main.rs
。
#Cargo.toml
[package]
name = "hello-world"
version = "0.1.0"
authors = [ "sunng@about.me" ]
//main.rs
fn main() {
println!("hello world");
}
构建项目不需要手动 rustc 了,那是上个世纪的东西,我们直接 cargo build
就可以:docker run -i -t -v $HOME/var/docker:/mnt/data -w /mnt/data/helloworld sunng/nightly cargo build
其中 -v
参数用于挂载目录,-w
参数指定执行的 pwd。
如果构建成功,就可以执行了,在 docker 中执行:docker run -i -t -v $HOME/var/docker:/mnt/data -w /mnt/data/helloworld sunng/nightly target/hello-world
其实可以直接在 host 系统里执行也是完全可以的:$HOME/var/docker/helloworld/target/hello-world
。
Web Hello World
前面说了 Rust 都有 web 框架了,我们就写一个 Web 版本的 Hello World 吧。这次用 Iron 框架,首先添加依赖到 Cargo 文件:
[package]
name = "hello-world"
version = "0.1.0"
authors = [ "sunng@about.me" ]
[dependencies.iron]
git = "https://github.com/iron/iron.git"
[dependencies.core]
git = "https://github.com/iron/core.git"
Cargo 目前还没有中央仓库,但是据说将来会有。目前还都是用 git 仓库来直接添加,所以构建环境里必须要有 git。
照着 Iron 的例子写一个最简单的 hello world 程序。
extern crate iron;
extern crate http;
use std::io::net::ip::Ipv4Addr;
use iron::{Iron, Server, Chain, Request, Response, Alloy, Status, Unwind, FromFn};
use http::status;
fn hello_world(_: &mut Request, res: &mut Response, _: &mut Alloy) -> Status {
res.serve(status::Ok, "Hello, world!");
Unwind
}
fn main() {
let mut server: Server = Iron::new();
server.chain.link(FromFn::new(hello_world));
server.listen(Ipv4Addr(127, 0, 0, 1), 3000);
}
编译 docker run -i -t -v $HOME/var/docker:/mnt/data -w /mnt/data/helloworld sunng/nightly cargo build
运行 docker run -i -t -v $HOME/var/docker:/mnt/data -w /mnt/data/helloworld -p 3000:3000 sunng/nightly target/hello-world
新增的参数-p
是把 docker 环境里的端口3000映射到 host 上的3000,这样我们才能在外面访问。
最后还有一个问题,因为程序听的是127.0.0.1,所以在 host 上是无法访问这个端口的,修改代码:
server.listen(Ipv4Addr(0, 0, 0, 0), 3000);
就可以正常工作了。
Wrap up
总结一下上面用 docker 比虚拟机的好处:
- 占用资源少,启动快
- 与 host 共享网络、硬盘都非常方便,满足开发需要不成问题
- 所有都是命令,与 host 系统上的进程集成也非常方便
- 支持镜像的版本控制和仓库