dig deeper, do different

2015-09-13
搞定 osx 下 virtualbox 中的 docker container 访问共享文件夹的权限问题

案例是这样的:

  • 有一台 osx 系统
  • 安装了 virtualbox 虚拟机
  • 在虚拟机里面装 Linux
  • 在 Linux 里面装了 docker
  • 用 docker 装了 Ubuntu 的 image
  • 在 Ubuntu 的 container 中装了 nginx

现在把OSX 下的一个 web 开发文件夹共享给 virtualbox下的 Linux,然后在通过 docker 映射到 container 下,nginx 的 root 目录指向这个文件夹,提供 web 服务。

但是问题来了,nginx 会报错说“permission denied”。在 container 下可以很明显的看到,共享文件夹中的内容是存放在了999这个 group 中。

分析一下原因,根源在于 virtualbox 从某一个版本开始,无法修改 osx 共享目录的权限了。可以看到,在 virtualbox 下的 Linux 中,共享文件夹的权限在一个叫做vboxsf的 group 下面。

以下是解决方法:

  • 在 container 下创建一个叫做vboxsf的 group: groupadd vboxsf
  • 修改这个 group 的 id 为999:vim /etc/group
  • 把 www-data 这个用户加入到vboxsf中:usermod -a -G vboxsf www-data
  • 重启 nginx:service nginx restart
Read More

2015-06-06
java压缩,javascript 解压缩总结

这里描述如何在 client 端使用 javascript 处理通过 ajax 调用返回的压缩数据。服务器端使用java 的DeflaterOutputStream来进行数据的压缩。

最早尝试使用jquery$.ajax方法来做 ajax 调用,但是其返回的数据都是字符串类型的,部分字节被强制转换了,导致这部分数据无法正确的解码。

如果仔细观察,浏览器的开发者模式中Response页面得到的数据格式是正常的,但是在 success: function (data)中数据是不正确的。

接收字节流而不是字符串

所以,如果需要 ajax 能够接收字节流而仅仅是字符串,需要使用 XMLHttpRequest自己来实现,v1和 v2都可以,下面给出的代码使用 v2的特性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function ajaxRequest (data) {
var request = new XMLHttpRequest();
request.open(data.type, data.url, true);
request.responseType = "arraybuffer";
request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
request.onload = function (event) {
if (data.success) {
data.success(request.response);
}
};
request.onerror = function (event) {
if (data.error) {
data.error(request.response);
}
};
request.send(data.data);
}

使用的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var szActionUrl = http_host + path;
var content = "userName=" + userName + "&password=" + password;
ajaxRequest({
url: szActionUrl,
type: "POST",
data: content,
success: function (data) {
console.log("success");
decodeToJson(data);
},
error: function (data) {
console.log("failed");
}
});

解压缩

解压缩使用的是 zlib,在使用前先加入引用:

1
<script language="JavaScript" type="text/javascript" src="zlip/inflate.min.js"></script>

javascript 的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function uintToString(uintArray) {
var encodedString = String.fromCharCode.apply(null, uintArray);
var decodedString = decodeURIComponent(escape(encodedString));
return decodedString;
}
function decodeToJson(data) {
var uintArray = new Uint8Array(data);
var inflate = new Zlib.Inflate(uintArray);
var plainArray = inflate.decompress();
var s = uintToString(plainArray);
console.log(s);
var result = JSON.parse(s);
return result;
}

其中的uintToString是用来把 Uint8Array转换成字符串,decodeURIComponent可以正确的处理 utf-8编码的字符。

Read More

2015-04-29
sftp用户创建与设置

环境:ubuntu server 14.04
目的:用户只能通过 sftp 访问指定目录,并且不能登录 shell

网上有很多这方面的介绍,最有价值的是这里。但是按照这篇文档还是遇到了两个坑:

  1. 配置没有加载
  2. sshd 无法正常启动

这并不能说是参考文章,只是它没有提到而已。解决方法在下面会以斜体的字体表明。

下面是需要的步骤;

创建用户组
1
sudo addgroup sftponly

之后将通过用户组来控制权限,所以创建一个新的用户组是有必要的。

创建用户
1
sudo useradd -d /home/bob -s /usr/lib/sftp-server -M -N -g sftponly bob

把新用户 bob 加入到 sftponly 这个用户组。

1
sudo passwd bob

为新用户 bob 设置密码。

1
echo "/usr/lib/sftp-server" >> /etc/shells

把 sftp-server 作为一个 shell 加入到 shell 列表。

创建用户目录
1
2
sudo mkdir -p /home/bob/uploads
sudo chown bob:sftponly /home/bob/uploads

为新用户创建 home 目录和 sftp 目录,并设置所有权。
需要注意的一点是,/home/bob 目录的 owner 需要是 root,权限最好是755

修改配置
1
sudo vim /etc/ssh/sshd_config

打开 sshd_config 配置文件,把 Subsystem sftp /usr/lib/openssh/sftp-server 注释掉,在下面加上 Subsystem sftp internal-sftp

最后一行添加上:

1
2
3
4
5
Match group sftponly
ChrootDirectory %h
X11Forwarding no
AllowTcpForwarding no
ForceCommand internal-sftp

注意:上面的代码一定要加在最有一行,否则 sshd 会无法启动

重启 sshd
1
sudo service ssh restart

注意:参考中使用sudo /etc/init.d/ssh restart来重启 sshd,没有任何的效果。

当使用 service 来重新启动的时候,如果正常会显示:

1
2
ssh stop/waiting
ssh start/running, process 12760

如果出错,则只会显示

1
2
ssh stop/waiting
ssh start/running

`

Read More

2015-04-22
docker之程序员系列 (一)

因为我主要使用 ubuntu 做服务器,所以以下的操作都是在 ubuntu server 14.04下进行。

OSX 下的选择

虽然官方提供了一个工具(boot2docker),但是说到底,它其实也是在 OSX 下使用 virtualbox 虚拟了一个 linux 出来,然后再在 linux 下进行 docker 操作。那么对于我这样的凡事都希望清晰、简单的人来说,第一选择肯定不会使用这个工具,而是会选择从头开始。如果你和我一样,那么我们需要下面这几样东西:

  1. virtualbox
  2. ubuntu server 14.04

linux 安装完成之后,为了更好的使用,你需要知道几件关于 virtualbox 的事情:

  1. 如何映射端口
  2. 在命令行启动虚拟机

映射端口在 virtualbox 的gui 界面中就可以简单的完成。下面我贴出命令行启动和保存虚拟机的代码:

1
VBoxManage startvm Ubuntu --type headless
1
VBoxManage controlvm Ubuntu savestate

Ubuntu 下 docker 安装和配置

docker 安装和配置和其他程序没有什么两样。使用apt-get进行安装:

1
2
sudo apt-get udpate
sudo apt-get install docker.io

此时 docker 的每次运行都需要加上前缀sudo,比较麻烦。可以进行如下的处理:

1
2
sudo groupadd docker
sudo gpasswd -a ${USER} docker

其中,USER替换成 ubuntu 的当前用户。具体可以参考 askubuntu.com

第一个 image

现在我们需要一个 image。这里也有几种选择:

  1. 从网上下载。如果网络速度比较快的话,可以使用下面的命令从 docker 官方库中搜索并拉一个 image 下来:

    1
    2
    docker search ubuntu
    docker pull ubuntu
  2. 自己做一个

如果你选择自己做一个,也是有多个选择,但这里我选择简单一点,使用 debootstrap 工具。而使用这个工具,不需要一个参数一个参数自己输入,docker 官方提供了一个脚本mkimage.sh

1
2
3
git clone https://github.com/docker/docker.git
cd docker
./mkimage.sh

按照提示进行即可。

运行容器

现在我们有了一个baseimage,在我们启动它之前,我们可以给它打一个 tag。

1
2
3
4
# 查看当前用于的 image
docker images
# 给 image 打 tag,格式为[repository[:tag]]
docker tag <image_id> ubuntu:14.04

当我们拥有多个 image 之后,可以很容易的通过 tag 来识别各自的用处。

1
2
# 运行这个 dock
docker run -it --name first ubuntu:14.04

这样就启动了一个容器,把这个容器命名为 first,并且获得一个控制台。

保存修改

容器的一大优势就是很方便的丢弃一些数据和状态。如果你只是临时性的运行一下程序,验证一些想法,容器是非常方便的。当退出并且删除容器之后,所有的数据都会被抛弃。
但是当你需要保存数据或是状态,那么需要显示的进行保存。docker 的一些概念和 git 相似,这里也是通过 commit 来保存容器:

1
docker commit first tag

tag可以是原来的 image 的 tag,也可以是一个新的 tag。

Read More

2015-04-18
blog 从 Dreamhost 搬到了 Linode

Dreamhost 从国内访问越来越差,速度慢不说,有时候还连不上。

除此之外,每月$8.5的共享服务器在价格方面也完全没有优势,没有 root 权限,很多东西都无法操作。

而且,虽然他们说硬盘大小是没有限制的,但是上次放了多一点东西就发邮件过来要求删除,说什么不能作为备份用途云云。

早有打算换一个服务商,只是一直没有找到合适的。这次买了 Linode 的 vps就把 blog 和 web 以及 git 都搬了过来。blog 也从 wordpress 换成了 hexo。因为 vps 上有足够的权限,分别做了 php 和 nginx 两个 docker 来支持这些服务。

Dreamhost 上现在只留下了域名服务,以后发现有更优惠的域名服务商之后再迁移出来。

Read More