<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Soul Of Free Loop &#187; 樱花</title>
	<atom:link href="https://zohead.com/archives/tag/sakura/feed" rel="self" type="application/rss+xml" />
	<link>https://zohead.com</link>
	<description>Uranus Zhou&#039;s Blog</description>
	<lastBuildDate>Sat, 19 Jul 2025 15:42:46 +0000</lastBuildDate>
	<language>zh-CN</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.8</generator>
	<item>
		<title>使用kcptun曲线访问Arukas容器</title>
		<link>https://zohead.com/archives/arukas-kcptun/</link>
		<comments>https://zohead.com/archives/arukas-kcptun/#comments</comments>
		<pubDate>Wed, 06 Mar 2019 17:08:16 +0000</pubDate>
		<dc:creator><![CDATA[Uranus Zhou]]></dc:creator>
				<category><![CDATA[网络]]></category>
		<category><![CDATA[Arukas]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Endpoint]]></category>
		<category><![CDATA[kcptun]]></category>
		<category><![CDATA[OpenWRT]]></category>
		<category><![CDATA[Shadowsocks]]></category>
		<category><![CDATA[容器]]></category>
		<category><![CDATA[樱花]]></category>

		<guid isPermaLink="false">https://zohead.com/?p=1573</guid>
		<description><![CDATA[新版 Arukas 容器现状 2017 年我写了两篇介绍日本 Arukas 樱花容器服务的文章，那个时候主要用来跑 Shadowsocks 梯子服务。后来不知道是否因为国内用户蜂拥而至，Arukas 容器基本所有的 IP 地址都被封了，接着 Arukas 也停止提供服务，直到去年才恢复。最近住处的移动宽带不知何故连接一直使用的美国 VPS 速度很慢，因此我想着可以试试新版本 Arukas 容器的效果。 恢复后的新版 Arukas 服务直接把原来的账户都给删除了，用户都需要重新注册，实际使用还必须绑定有效的信用卡，容器配置可以参考其官网（需要爬墙）： https://arukas.io/en/# [&#8230;]]]></description>
				<content:encoded><![CDATA[<h2 id="new-arukas">新版 Arukas 容器现状</h2>
<p>2017 年我写了两篇介绍日本 <a href="https://zohead.com/archives/tag/arukas/">Arukas</a> 樱花容器服务的文章，那个时候主要用来跑 Shadowsocks 梯子服务。后来不知道是否因为国内用户蜂拥而至，Arukas 容器基本所有的 IP 地址都被封了，接着 Arukas 也停止提供服务，直到去年才恢复。最近住处的移动宽带不知何故连接一直使用的美国 VPS 速度很慢，因此我想着可以试试新版本 Arukas 容器的效果。</p>
<p>恢复后的新版 Arukas 服务直接把原来的账户都给删除了，用户都需要重新注册，实际使用还必须绑定有效的信用卡，容器配置可以参考其官网（需要爬墙）：</p>
<p><a href="https://arukas.io/en/#pricing" target="_blank">https://arukas.io/en/#pricing</a></p>
<p>每个账户可以最多创建一个免费容器，免费容器配置如下：</p>
<ul>
<li>每个月 730 小时运行时间；</li>
<li>0.1 vCPU；</li>
<li>128 MB 内存；</li>
<li>100 GB 流量；</li>
<li>仍然不支持外部存储；</li>
<li>支持绑定域名（针对 Endpoint）；</li>
<li>仍然只支持 Docker Hub 库，而且只支持修改 <code>CMD</code> 启动命令。</li>
</ul>
<p>可以看到新版 Arukas 免费容器的配置是有点捉襟见肘，还好我也只是拿来访问 Google 服务之类的，对流量需求不大，如果你经常要看 YouTube 视频之类的，那就不用考虑 Arukas 容器咯。</p>
<p>按照原来写的 <a href="https://zohead.com/archives/arukas-ge-tt/">Arukas容器使用ge.tt替代Endpoint域名</a> 文章重新部署 Shadowsocks 容器，我发现还算欣慰的是 Arukas 提供的 Endpoint 域名还没有被封锁，容器内 Web 服务器提供的内容可以通过 Endpoint 域名访问。</p>
<p>如果你只需要跑一个简单的静态网站，对资源和流量要求也不高的话，那 Arukas 容器也是挺不错的，毕竟还支持绑定自定义的域名。不过 Arukas 的 Endpoint 域名转发服务仍然只支持 HTTPS 访问，而且 Endpoint 地址应该只对容器开放的第一个内部端口有效，只支持 HTTP 协议，不支持 TCP 或者 UDP。如果用 Arukas 容器来跑动态网站，那有可能效果不太理想。</p>
<p>不出意料的是我准备搭梯子的时候，发现墙对 Arukas 封锁的比较彻底，测试了多个 IP 地址都无法正常连接，为此考虑修改原来的容器试试通过 kcptun 进行转发访问。</p>
<h2 id="arukas-shadowsocks-mod">Shadowsocks 容器修改</h2>
<p>我原来制作的 Arukas 专用 Shadowsocks 容器是基于 <a href="https://github.com/phusion/baseimage-docker" target="_blank">Baseimage-docker</a> 镜像修改的，增加 kcptun 支持也很简单。访问 kcptun 的官方 GitHub release 页面：</p>
<p><a href="https://github.com/xtaci/kcptun/releases" target="_blank">https://github.com/xtaci/kcptun/releases</a></p>
<p>下载 Linux amd64 版本的 kcptun 程序，我们也只需要将服务端程序加到原来的 Shadowsocks 容器镜像中，并简单修改下 <code>/etc/my_init.d/01_start_ss_ssh.sh</code> 启动脚本（支持 kcptun 的修改已高亮显示）：</p>
<pre class="brush: bash; title: ; notranslate">
#!/bin/bash

# Enable SSH
rm -f /etc/service/sshd/down
/etc/my_init.d/00_regen_ssh_host_keys.sh
touch /etc/service/sshd/down

# Setup SSH key
if [ &quot;x$SSH_AUTHORIZED_KEYS&quot; = &quot;x&quot; ]; then
	/usr/sbin/enable_insecure_key
else
	mkdir ~/.ssh
	echo &quot;$SSH_AUTHORIZED_KEYS&quot; | sed 's/\\n/\n/g' &gt; ~/.ssh/authorized_keys
	chmod 400 ~/.ssh/authorized_keys
fi

# Start web server
env | grep -E '^MARATHON_HOST=|MARATHON_PORT_' &gt; /home/wwwroot/default/marathon.conf
if [ &quot;x$MARATHON_HOST&quot; != &quot;x&quot; ]; then
	getent hosts $MARATHON_HOST | awk '{print &quot;MARATHON_HOST_IP=&quot;$1; exit;}' &gt;&gt; /home/wwwroot/default/marathon.conf
fi

start-stop-daemon -S -b -n tmp-httpd -d /home/wwwroot/default -x /usr/bin/python3 -- -m http.server 80

# Start ShadowSocks
env | grep '^SHADOWSOCKS_CFGS_' | awk -F '=' '{print $1;}' | while read T_NAME; do
	SS_NAME=&quot;${T_NAME:17}&quot;
	echo &quot;${!T_NAME}&quot; &gt; /etc/shadowsocks-libev/${SS_NAME}.json
	start-stop-daemon -n ss-$SS_NAME -x /usr/bin/ss-server -b -S -- -c /etc/shadowsocks-libev/${SS_NAME}.json -u --fast-open
done

# Start kcptun
env | grep '^KCPTUN_CFGS_' | awk -F '=' '{print $1;}' | while read T_NAME; do
	KCP_NAME=&quot;${T_NAME:12}&quot;
	echo &quot;${!T_NAME}&quot; &gt; /etc/kcptun/${KCP_NAME}.json
	start-stop-daemon -n kcp-$KCP_NAME -x /usr/bin/kcptun_server -b -S -- -c /etc/kcptun/${KCP_NAME}.json
done

if [ &quot;x$GETT_TOKEN&quot; != &quot;x&quot; ]; then
	if [ &quot;x$HOME&quot; = &quot;x&quot; ]; then
		export HOME=&quot;/root&quot;
	fi
	echo -n &quot;$GETT_TOKEN&quot; &gt; ~/.gett-token
	if [ &quot;x$GETT_SHARE_NAME&quot; != &quot;x&quot; ]; then
		python3 /usr/local/gett/uploader.py -l http://ge.tt/$GETT_SHARE_NAME | awk '{if (substr($5,1,13)==&quot;http://ge.tt/&quot;) {print $5;}}' | xargs python3 /usr/local/gett/uploader.py --delete
		python3 /usr/local/gett/uploader.py -s http://ge.tt/$GETT_SHARE_NAME /home/wwwroot/default/marathon.conf
	fi
fi

exec /usr/sbin/sshd -D -e -u 0
</pre>
<p>新版支持 kcptun 访问 Shadowsocks 的 Arukas 专用容器安装包下载地址，仍然支持 SSH 登录以及通过 Endpoint 地址或者 <a href="https://zohead.com/archives/ge-tt-cli-api/">ge.tt</a> 分享获取容器当前地址和端口：</p>
<p><a href="https://zohead.com/downloads/arukas-baseimage-xenial-ss.tar.gz">https://zohead.com/downloads/arukas-baseimage-xenial-ss.tar.gz</a></p>
<p>原有的 <code>CMD</code> 启动命令以及以 <code>SHADOWSOCKS_CFGS_</code> 开头的 Shadowsocks 配置变量和 <code>SSH_AUTHORIZED_KEYS</code> SSH 证书变量配置都没有变化。</p>
<p>此次增加了以 <code>KCPTUN_CFGS_</code> 开头的 kcptun 配置变量，当然别忘了容器端口配置中也得指定一个新的 UDP 端口给 kcptun 服务使用。</p>
<p>例如我现有的 Shadowsocks 服务配置变量：</p>
<pre class="brush: jscript; title: ; notranslate">
SHADOWSOCKS_CFGS_xxx={ &quot;server&quot;:&quot;0.0.0.0&quot;, &quot;server_port&quot;:17374, &quot;local_port&quot;:1080, &quot;password&quot;:&quot;arukas-ss-svr&quot;, &quot;timeout&quot;:30, &quot;method&quot;:&quot;aes-256-cfb&quot; }
</pre>
<p>现在需要在 Arukas 容器中运行 kcptun 服务器进行 UDP 转发，可以添加一个 kcptun 配置变量（仍然是 JSON 格式，需要写成一行）：</p>
<pre class="brush: jscript; title: ; notranslate">
KCPTUN_CFGS_xxx = { &quot;listen&quot;: &quot;:29900&quot;, &quot;target&quot;: &quot;127.0.0.1:17374&quot;, &quot;key&quot;: &quot;arukas-kcp-svr&quot;, &quot;crypt&quot;: &quot;xor&quot;, &quot;mode&quot;: &quot;fast2&quot;, &quot;mtu&quot;: 1350, &quot;sndwnd&quot;: 128, &quot;rcvwnd&quot;: 128, &quot;datashard&quot;: 0, &quot;parityshard&quot;: 0, &quot;dscp&quot;: 46, &quot;nocomp&quot;: true, &quot;acknodelay&quot;: false, &quot;nodelay&quot;: 0, &quot;interval&quot;: 40, &quot;resend&quot;: 2, &quot;nc&quot;: 1, &quot;sockbuf&quot;: 4194304, &quot;keepalive&quot;: 10, &quot;log&quot;: &quot;/var/log/kcptun.log&quot; }
</pre>
<p>这里我指定 kcptun 服务器绑定默认的 29900 UDP 端口（Arukas 容器端口配置中即需要开放 29900 UDP 端口），转发地址即指向本地的 Shadowsocks 服务器端口。</p>
<blockquote>
<p><strong>提示</strong></p>
<p>上面贴出来的我使用的 kcptun 配置并不是最佳配置，只是由于我的 OpenWRT 路由器运算能力比较孱弱，避免出现路由器上的 kcptun 客户端导致 CPU 占用过高的问题。</p>
<p>kcptun 的配置稍微有点复杂，需要根据用户实际网络环境修改，这里我就不详细介绍了，请参考 <a href="https://github.com/xtaci/kcptun" target="_blank">GitHub</a> 项目主页的说明。</p>
</blockquote>
<h2 id="android-kcptun-test">Android kcptun 测试</h2>
<p>我们可以首先用 Android 手机测试通过 kcptun 连接 Arukas 容器的 Shadowsocks 服务，在手机上安装 <a href="https://play.google.com/store/apps/details?id=com.github.shadowsocks" target="_blank">Shadowsocks</a> App 和专用的 <a href="https://play.google.com/store/apps/details?id=com.github.shadowsocks.plugin.kcptun" target="_blank">kcptun</a> 插件。</p>
<p>安装完成之后 Shadowsocks 配置文件中就可以选择 kcptun 插件，需要注意你如果使用的是像我的 Nubia Z17 这种魔改版手机，可能需要在 <strong>手机管家</strong> 之类的系统设置中开启 kcptun 的自启动权限，防止出现 Shadowsocks App 无法启动 kcptun 的问题。</p>
<p>Shadowsocks App 连接的服务器地址也需要更换为 Arukas 容器实际地址和 kcptun 服务的外部访问端口，kcptun 插件的配置则保持与服务端一致即可，我的配置如下：</p>
<pre class="brush: plain; title: ; notranslate">
dscp=46;nocomp;mtu=1350;datashard=0;parityshard=0;mode=fast2;key=arukas-kcp-svr;crypt=xor
</pre>
<p>Android kcptun 插件的配置使用 <code>key=value</code> 的格式，中间以分号隔开，如果只有 <code>key</code> 没有 <code>value</code> 则表示启用该参数（true），具体配置参数可以点击 kcptun 插件的 <code>?</code> 按钮查看详细说明。</p>
<h2 id="openwrt-kcptun-script">OpenWRT 自动更新配置脚本</h2>
<p>使用 kcptun 之后，OpenWRT 路由器上的 Shadowsocks 配置也不太一样了，例如我的 <code>/etc/shadowsocks-arukas.json</code> 配置文件就可以保持不变了（固定连接本地 kcptun 地址和端口）：</p>
<pre class="brush: jscript; title: ; notranslate">
{
	&quot;server&quot; : &quot;127.0.0.1&quot;,
	&quot;server_port&quot; : &quot;17374&quot;,
	&quot;password&quot;: &quot;arukas-ss-svr&quot;,
	&quot;local_port&quot;: &quot;1080&quot;,
	&quot;timeout&quot; : &quot;30&quot;,
	&quot;method&quot;: &quot;aes-256-cfb&quot;
}
</pre>
<p>相应的增加 kcptun 客户端的配置文件 <code>/etc/kcptun-arukas.json</code>，<code>key</code> 密码与容器中 kcptun 服务器密码一致，<code>remoteaddr</code> 就是容器 kcptun 服务 UDP 监听的外部访问地址和端口：</p>
<pre class="brush: jscript; title: ; notranslate">
{
&quot;localaddr&quot;: &quot;:17374&quot;,
&quot;remoteaddr&quot;: &quot;&quot;,
&quot;key&quot;: &quot;arukas-kcp-svr&quot;,
&quot;crypt&quot;: &quot;xor&quot;,
&quot;mode&quot;: &quot;fast2&quot;,
&quot;mtu&quot;: 1350,
&quot;sndwnd&quot;: 128,
&quot;rcvwnd&quot;: 128,
&quot;datashard&quot;: 0,
&quot;parityshard&quot;: 0,
&quot;dscp&quot;: 46,
&quot;nocomp&quot;: true,
&quot;acknodelay&quot;: false,
&quot;nodelay&quot;: 0,
&quot;interval&quot;: 40,
&quot;resend&quot;: 2,
&quot;nc&quot;: 1,
&quot;sockbuf&quot;: 4194304,
&quot;keepalive&quot;: 10
}
</pre>
<p>为了支持 kcptun，我也稍微改了下 OpenWRT 路由器的 <code>arukas-ss.sh</code> 自动更新配置脚本，为了使用方便我把 kcptun 客户端的启动和停止操作也放到 <code>/etc/init.d/shadowsocks</code> 服务脚本中了，其它路由器请自行修改此脚本：</p>
<pre class="brush: bash; title: ; notranslate">
#!/bin/sh
ARUKAS_ENDPOINT=&quot;&quot;
GETT_SHRNAME=&quot;&quot;
RESTART_SHADOWSOCKS=&quot;no&quot;

[ $# -ge 2 ] || exit 1

[ -f /tmp/.marathon.conf ] &amp;&amp; mv /tmp/.marathon.conf /tmp/.marathon.conf.bak

IND=0
while [ $IND -lt 5 ]; do
	let IND++
	[ -f /tmp/.marathon.conf ] &amp;&amp; rm -f /tmp/.marathon.conf
	if [ &quot;x$GETT_SHRNAME&quot; != &quot;x&quot; ]; then
		T_FILEID=`curl -s -k -f http://api.ge.tt/1/shares/$GETT_SHRNAME | sed -e 's/^.*&quot;fileid&quot;[^:]*:[^&quot;]*&quot;//' -e 's/&quot;.*$//'`
		if [ &quot;x$T_FILEID&quot; != &quot;x&quot; ]; then
			curl -s -k -f -o /tmp/.marathon.conf -L -e &quot;http://ge.tt/$GETT_SHRNAME&quot; &quot;http://api.ge.tt/1/files/$GETT_SHRNAME/$T_FILEID/blob?download&quot;
			[ $? -eq 0 ] &amp;&amp; break
		fi
	fi
	curl -s -k -f -o /tmp/.marathon.conf https://$ARUKAS_ENDPOINT.arukascloud.io/marathon.conf
	[ $? -eq 0 ] &amp;&amp; break
	sleep 1
done

[ -s /tmp/.marathon.conf ] || exit 1
echo &quot;Fetch server config after $IND tries.&quot;

if [ -f /tmp/.marathon.conf.bak ]; then
	cmp -s /tmp/.marathon.conf /tmp/.marathon.conf.bak
	if [ $? -eq 0 ]; then
		rm -f /tmp/.marathon.conf
		exit 0
	fi
fi

. /tmp/.marathon.conf 2&gt;/dev/null
if [ &quot;x$MARATHON_HOST&quot; = &quot;x&quot; ]; then
	rm -f /tmp/.marathon.conf
	exit 1
fi

if [ &quot;x$MARATHON_HOST_IP&quot; != &quot;x&quot; ]; then
	MARATHON_HOST=&quot;$MARATHON_HOST_IP&quot;
fi

while [ $# -gt 2 ]; do
	CMD=&quot;echo \${MARATHON_PORT_$2}&quot;
	TMP_PORT=`eval $CMD`

	if [ -f $1 -a &quot;x$TMP_PORT&quot; != &quot;x&quot; ]; then
		if [ &quot;x$3&quot; = &quot;xshadowsocks&quot; ]; then
			sed -i -e 's/&quot;server&quot;[^:]*:[^,]*,/&quot;server&quot; : &quot;'$MARATHON_HOST'&quot;,/' -e 's/&quot;server_port&quot;[^:]*:[^,]*,/&quot;server_port&quot; : &quot;'$TMP_PORT'&quot;,/' $1
			grep -q '^CONFIG.*='$1 /etc/init.d/shadowsocks
			[ $? -eq 0 ] &amp;&amp; RESTART_SHADOWSOCKS=&quot;yes&quot;
		elif [ &quot;x$3&quot; = &quot;xkcptun&quot; ]; then
			sed -i 's/&quot;remoteaddr&quot;[^:]*:[^,]*,/&quot;remoteaddr&quot; : &quot;'$MARATHON_HOST':'$TMP_PORT'&quot;,/' $1
			grep -q '^KCPTUN_CONFIG.*='$1 /etc/init.d/shadowsocks
			[ $? -eq 0 ] &amp;&amp; RESTART_SHADOWSOCKS=&quot;yes&quot;
		fi
	fi
	shift
	shift
	shift
done

if [ &quot;x$RESTART_SHADOWSOCKS&quot; = &quot;xyes&quot; ]; then
	/etc/init.d/shadowsocks restart
fi
</pre>
<p>使用之前请修改脚本最上面的 <code>ARUKAS_ENDPOINT</code> 和 <code>GETT_SHRNAME</code> 变量，分别为 Arukas 容器的 Endpoint 名（Arukas Endpoint 地址可访问的情况下建议优先使用）和 ge.tt 分享名。</p>
<p>为了区分 Shadowsocks 和 kcptun 配置文件，我对脚本调用方式也做了修改，增加了指定配置类型的参数（<code>shadowsocks</code> 或 <code>kcptun</code>），例如我的 crontab 配置：</p>
<pre class="brush: plain; title: ; notranslate">
30 * * * * /etc/arukas-ss.sh /etc/kcptun-arukas.json 29900 kcptun
</pre>
<p>这样路由器就可以自动更新 kcptun 客户端配置文件中的 <code>remoteaddr</code> 项了。</p>
<p>我的渣渣移动宽带环境下电脑通过路由器 kcptun 爬墙看 YouTube 视频效果如下：</p>
<p><img src="http://res.cloudinary.com/digwht2y0/image/upload/v1737442943/shadowsocks-kcptun-speed.png" alt="Arukas 容器 Shadowsocks kcptun 速度"></p>
<p>受限于路由器硬件的性能，Arukas 网络的 kcptun 速度并没有完全发挥出来，不过还是比原先的美国 VPS 要好多了，最后祝大家在开会的特殊阶段也能把梯子搭的开心。</p>
]]></content:encoded>
			<wfw:commentRss>https://zohead.com/archives/arukas-kcptun/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Arukas樱花Docker容器及Endpoint体验</title>
		<link>https://zohead.com/archives/arukas-container/</link>
		<comments>https://zohead.com/archives/arukas-container/#comments</comments>
		<pubDate>Fri, 31 Mar 2017 16:17:46 +0000</pubDate>
		<dc:creator><![CDATA[Uranus Zhou]]></dc:creator>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[Arukas]]></category>
		<category><![CDATA[Endpoint]]></category>
		<category><![CDATA[OpenWRT]]></category>
		<category><![CDATA[Shadowsocks]]></category>
		<category><![CDATA[容器]]></category>
		<category><![CDATA[樱花]]></category>

		<guid isPermaLink="false">https://zohead.com/?p=1408</guid>
		<description><![CDATA[Arukas 容器介绍 之前我在了解目前主流的容器服务商时除了 IBM Bluemix 还知道了日本 Arukas 容器，不过一直都没有测试的机会，最近 Arukas 难得给我发了注册通过的邮件，最新的政策显示免费测试期会延长到 2017 年 6 月 30 日（未来收费策略待定）。 下面的基本操作都在 Arukas 控制面板： https://app.arukas.io/ Arukas 容器限制 Arukas 容器还处于免费测试阶段，有一些限制需要先说明： 不支持特权容器，无法使用 TUN/TAP 设备（目前的容器服务商基本都不支持）； 没有固定公网 IP 地址，容器可能每隔几天甚至几个小时就 [&#8230;]]]></description>
				<content:encoded><![CDATA[<h2 id="arukas-intro">Arukas 容器介绍</h2>
<p>之前我在了解目前主流的容器服务商时除了 IBM Bluemix 还知道了日本 Arukas 容器，不过一直都没有测试的机会，最近 Arukas 难得给我发了注册通过的邮件，最新的政策显示免费测试期会延长到 2017 年 6 月 30 日（未来收费策略待定）。</p>
<p>下面的基本操作都在 Arukas 控制面板：</p>
<p><a href="https://app.arukas.io/" target="_blank">https://app.arukas.io/</a></p>
<h3 id="arukas-limits">Arukas 容器限制</h3>
<p>Arukas 容器还处于免费测试阶段，有一些限制需要先说明：</p>
<ul>
<li>不支持特权容器，无法使用 TUN/TAP 设备（目前的容器服务商基本都不支持）；</li>
<li>没有固定公网 IP 地址，容器可能每隔几天甚至几个小时就会重启；</li>
<li>配置的容器内部端口会被映射到随机的外部端口；</li>
<li>自定义 Endpoint 域名只能以 HTTPS 方式访问，对应的容器内部端口只支持 HTTP 协议（下面会详细介绍）；</li>
<li>不支持使用自定义的 <code>Dockerfile</code> 文件构建容器，只能使用 Docker hub 上的镜像；</li>
<li>暂时不支持外部存储，因此容器里无法保存任何数据，每次重启容器数据会全部丢失；</li>
<li>创建容器时只能配置 <code>Dockerfile</code> 中的 <code>ENV</code>（环境变量）和 <code>CMD</code>（启动执行命令）指令，不支持 <code>RUN</code> 及 <code>ENTRYPOINT</code> 等其它指令。</li>
</ul>
<h3 id="about-endpoint">关于 Endpoint</h3>
<p>通过参考 Arukas 日文版帮助文档，我们可以得知虽然 Arukas 容器没有固定的公网 IP 地址，容器开放的内部端口每次启动也都被映射到随机的外部端口，但容器的 Endpoint 地址是始终固定不变的，类似于这样：</p>
<pre class="brush: plain; title: ; notranslate">

https://xxx.arukascloud.io/

</pre>
<p>经过测试我发现容器的 Endpoint 地址必须以 HTTPS 方式访问（HTTP 访问会直接返回 Connection refused），Endpoint 地址只对容器开放的第一个内部端口有效，而且该内部端口只支持 HTTP 协议，不支持 TCP 或者 UDP。</p>
<p>用户访问 Endpoint 子域名地址时并不是直接访问容器的当前公网地址，而是访问 Arukas 提供的 HAProxy 负载均衡服务器，HAProxy 负责转发并均衡容器下多个实例的 HTTP 请求，其网络拓扑图大概如下所示：</p>
<p><img src="http://res.cloudinary.com/digwht2y0/image/upload/v1737370568/arukas-endpoint.png" alt="Arukas Endpoint 网络拓扑图" title="Arukas Endpoint 网络拓扑图"></p>
<blockquote>
<p><strong>提示</strong></p>
<p>Arukas 官网上对 Endpoint 的说明遗漏了比较重要的一点：如果容器配置里开启了多个对外开放的内部端口，那么 Endpoint 请求转发只会在所有这些端口的服务都已经运行的情况下才有效。</p>
</blockquote>
<p>这样 Arukas 就能够在有限的服务器（内部端口映射到随机外部端口）和公网 IP 地址（固定 Endpoint 地址）情况下提供尽量多的容器访问支持。</p>
<h2 id="build-container">构建容器</h2>
<p>从上面的介绍来看虽然 Arukas 容器有很多体验不太好的限制，但其所在的樱花机房线路还是相当有吸引力的，立马准备建立容器看看运行效果。</p>
<p>为了测试 Arukas 容器的运行效果，我没有使用一些做好的通用 SSH 系统（例如：centos-ssh）或者 Shadowsocks 系统镜像，本文还是用的之前捣鼓过的 <a href="https://github.com/phusion/baseimage-docker" target="_blank">baseimage-docker</a> Docker 镜像。</p>
<h3 id="baseimage-docker-problem">baseimage-docker 的问题</h3>
<p>baseimage-docker 镜像虽然用起来很方便，支持轻量级的 <a href="http://smarden.org/runit/" target="_blank"><code>runit</code></a> 服务管理方案，但该镜像默认并没有开启 SSH 登录，如果需要开启 SSH 服务器或者执行自定义命令都需要修改 <code>Dockerfile</code> 文件中的 <code>RUN</code> 指令，具体可以参考该项目 GitHub 主页。</p>
<p>然而 Arukas 容器并不支持使用 <code>RUN</code> 命令配置执行自定义命令，也不能保存任何数据，因此 SSH 登录和执行自定义命令的问题需要通过其它方法解决。</p>
<p>幸好 baseimage-docker 还支持通过 <code>CMD</code> 指令开启运行 <a href="https://github.com/phusion/baseimage-docker#oneshot" target="_blank">one-shot command</a> 单次命令支持，对应的 <code>CMD</code> 指令类似这样：</p>
<pre class="brush: bash; title: ; notranslate">
/sbin/my_init -- COMMAND ARGUMENTS ...
</pre>
<p>容器系统的运行流程就相当于：</p>
<ul>
<li>运行所有启动脚本，例如 <code>/etc/my_init.d/*</code> 及 <code>/etc/rc.local</code>；</li>
<li>启动所有 <code>runit</code> 服务；</li>
<li>运行 <code>my_init</code> 参数中指定的自定义命令；</li>
<li>自定义命令退出之后即停止所有 <code>runit</code> 服务。</li>
</ul>
<p>因此我们可以在单次命令参数上做文章，实现开启 SSH 服务器、安装需要的软件并启动附加的服务。</p>
<h3 id="container-config">容器基本配置</h3>
<p>下面是我在 Arukas 控制面板建立的一个 Shadowsocks 服务器容器的配置：</p>
<p><img src="http://res.cloudinary.com/digwht2y0/image/upload/v1737370567/arukas-docker-config.png" alt="Arukas 容器配置" title="Arukas Endpoint 容器配置"></p>
<ul>
<li><strong>Image</strong> 我使用的是最新的 baseimage-docker 镜像：<code>phusion/baseimage:0.9.19</code>；</li>
<li><strong>Instances</strong> 一般就用默认的一个实例；</li>
<li><strong>Memory</strong> 可以根据需要选择 256 MB 或者 512 MB；</li>
<li><strong>Endpoint</strong> 指定 Endpoint 子域名地址；</li>
<li><strong>Port</strong> 设置里可以将容器中最多 20 个 TCP 或者 UDP 端口对外开放，我填了 80、22 外加一个 Shadowsocks 服务器端口，需要注意的就是上面的固定 Endpoint 地址只支持第一个端口；</li>
<li><strong>ENV</strong> 环境变量根据需要设置，我在这里指定了 SSH key 和 Shadowsocks 服务器配置；</li>
<li>
<p><strong>CMD</strong> 设置比较关键，我建立的 Shadowsocks 测试容器是这样的：</p>
<pre class="brush: bash; title: ; notranslate">
/sbin/my_init -- sh -c 'curl -o /arukas-baseimage-xenial-ss.tar.gz https://zohead.com/downloads/arukas-baseimage-xenial-ss.tar.gz &amp;&amp; tar -C / -xzf /arukas-baseimage-xenial-ss.tar.gz &amp;&amp; /etc/my_init.d/01_start_ss_ssh.sh'
</pre>
</li>
</ul>
<p>我制作了一个适用于最新 baseimage 系统的 Shadowsocks 服务器安装包：</p>
<p><a href="https://zohead.com/downloads/arukas-baseimage-xenial-ss.tar.gz">https://zohead.com/downloads/arukas-baseimage-xenial-ss.tar.gz</a></p>
<p>容器系统启动时会自动将安装包下载到根目录下解压缩，然后执行其中的 <code>/etc/my_init.d/01_start_ss_ssh.sh</code> 启动脚本：</p>
<pre class="brush: bash; title: ; notranslate">
#!/bin/bash

# Enable SSH
rm -f /etc/service/sshd/down
/etc/my_init.d/00_regen_ssh_host_keys.sh
touch /etc/service/sshd/down

# Setup SSH key
if [ &quot;x$SSH_AUTHORIZED_KEYS&quot; = &quot;x&quot; ]; then
	/usr/sbin/enable_insecure_key
else
	mkdir ~/.ssh
	echo &quot;$SSH_AUTHORIZED_KEYS&quot; | sed 's/\\n/\n/g' &gt; ~/.ssh/authorized_keys
	chmod 400 ~/.ssh/authorized_keys
fi

# Start web server
env | grep -E '^MARATHON_HOST=|MARATHON_PORT_' &gt; /home/wwwroot/default/marathon.conf
if [ &quot;x$MARATHON_HOST&quot; != &quot;x&quot; ]; then
	getent hosts $MARATHON_HOST | awk '{print &quot;MARATHON_HOST_IP=&quot;$1; exit;}' &gt;&gt; /home/wwwroot/default/marathon.conf
fi

start-stop-daemon -S -b -n tmp-httpd -d /home/wwwroot/default -x /usr/bin/python3 -- -m http.server 80

# Start ShadowSocks
env | grep '^SHADOWSOCKS_CFGS_' | awk -F '=' '{print $1;}' | while read T_NAME; do
	SS_NAME=&quot;${T_NAME:17}&quot;
	echo &quot;${!T_NAME}&quot; &gt; /etc/shadowsocks-libev/${SS_NAME}.json
	start-stop-daemon -n ss-$SS_NAME -x /usr/bin/ss-server -b -S -- -c /etc/shadowsocks-libev/${SS_NAME}.json -u --fast-open
done

exec /usr/sbin/sshd -D -e -u 0
</pre>
<p>该启动脚本的执行流程如下：</p>
<ul>
<li>首先启用 SSH 服务器，并产生 SSH host key；</li>
<li>如果容器配置的 <strong>ENV</strong> 环境变量里存在 <code>SSH_AUTHORIZED_KEYS</code> 变量，那么就使用这个变量的内容作为 SSH 公钥（容器配置截图里我就使用此方法指定自定义公钥），如果不存在则使用 baseimage 提供的默认公钥；</li>
<li>接着获取 Arukas 容器的当前临时域名、公网 IP 地址以及每个内部端口映射等内容输出到 <code>/home/wwwroot/default</code> Web 服务器目录下的 <code>marathon.conf</code> 文件；</li>
<li>在默认的 80 端口启动 Web 服务器以支持 Endpoint 地址访问；</li>
<li>
<p>遍历容器配置的所有 <strong>ENV</strong> 环境变量，如果存在以 <code>SHADOWSOCKS_CFGS_</code> 开头的变量，就在 <code>/etc/shadowsocks-libev</code> 目录下生成 Shadowsocks 服务器配置文件，配置文件内容就是该变量的值。</p>
<p>例如我使用的一个 Shadowsocks 配置变量（将 Shadowsocks 服务器的 JSON 配置写成一行）：</p>
<pre class="brush: jscript; title: ; notranslate">
SHADOWSOCKS_CFGS_xxx={ &quot;server&quot;:&quot;0.0.0.0&quot;, &quot;server_port&quot;:17374, &quot;local_port&quot;:1080, &quot;password&quot;:&quot;arukas-ss-svr&quot;, &quot;timeout&quot;:30, &quot;method&quot;:&quot;aes-256-cfb&quot; }
</pre>
<p>这样就会自动产生 <code>/etc/shadowsocks-libev/xxx.json</code> 配置文件；</p>
</li>
<li>依次启动 <strong>ENV</strong> 环境变量里指定的所有 Shadowsocks 服务器（可以指定多个以 <code>SHADOWSOCKS_CFGS_</code> 开头的变量）；</li>
<li>最后以前台方式启动 SSH 服务器，这样就能实现 SSH 远程登录，而且 baseimage 容器也不会退出。</li>
</ul>
<h3 id="container-status">容器运行状态</h3>
<p>Arukas 容器启动运行成功之后，你可以在控制面板里查看运行状态：</p>
<p><img src="http://res.cloudinary.com/digwht2y0/image/upload/v1737370567/arukas-docker-status.png" alt="Arukas 容器运行状态" title="Arukas Endpoint 容器运行状态"></p>
<p>这里可以看到容器的 Endpoint 地址、用于直接访问容器的临时域名和映射的外部端口等信息。</p>
<p>容器启动之后会将当前的临时域名、内部端口映射等信息输出到系统环境变量中，这样上面的 <code>/etc/my_init.d/01_start_ss_ssh.sh</code> 启动脚本才能直接获取到这些信息，有兴趣的朋友可以在容器中确认：</p>
<pre class="brush: bash; title: ; notranslate">
root@02a78258745b:~# env | grep -E '^MARATHON|MESOS'
MESOS_TASK_ID=db89b5a5-7df0-49f0-b5d4-47d6406abbd8.6cccf318-080c-11e7-aca2-0242a39fa0e7
MARATHON_PORT0=31198
MARATHON_PORT1=31689
MARATHON_PORT=31198
MARATHON_APP_RESOURCE_DISK=0.0
MARATHON_APP_RESOURCE_MEM=32.0
MARATHON_APP_LABEL_HAPROXY_0_VHOST=gloomy-golick-3736.arukascloud.io
MARATHON_APP_RESOURCE_GPUS=0
MESOS_CONTAINER_NAME=mesos-eb1747b8-0843-4061-bc0e-9cd1b5347ee2-S9.d07c30b6-51b1-44ca-a453-d4302ec08d2e
MARATHON_APP_LABEL_HAPROXY_GROUP=external
MARATHON_HOST=seaof-153-125-239-206.jp-tokyo-27.arukascloud.io
MARATHON_APP_LABELS=HAPROXY_GROUP HAPROXY_0_VHOST
MARATHON_APP_ID=/db89b5a5-7df0-49f0-b5d4-47d6406abbd8
MARATHON_APP_DOCKER_IMAGE=phusion/baseimage:0.9.19
MARATHON_APP_VERSION=2017-03-13T16:45:10.089Z
MARATHON_PORTS=31198,31689
MARATHON_APP_RESOURCE_CPUS=0.01
MARATHON_PORT_80=31198
MARATHON_PORT_22=31689
MESOS_SANDBOX=/mnt/mesos/sandbox
</pre>
<p>我们可以看看 Arukas 容器的服务器信息，其使用的是 CoreOS 系统（内核版本为 4.9.9）：</p>
<pre class="brush: bash; title: ; notranslate">
root@837bc28c1c36:~# uname -a
Linux 837bc28c1c36 4.9.9-coreos-r1 #1 SMP Tue Mar 28 22:27:48 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
</pre>
<p>内存是所有容器一起共享的（如果容器使用的内存超过配置中的限制太多会被重启）：</p>
<pre class="brush: bash; title: ; notranslate">
root@837bc28c1c36:~# free -m
              total        used        free      shared  buff/cache   available
Mem:          24115        4300        1520         715       18295       17563
Swap:          4095          24        4071
</pre>
<p>CPU 配置还算给力，使用的是 8 个 Xeon E5-2650：</p>
<pre class="brush: bash; title: ; notranslate">
root@837bc28c1c36:~# grep -E '^processor|physical id|model name' /proc/cpuinfo
processor	: 0
model name	: Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz
physical id	: 0
processor	: 1
model name	: Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz
physical id	: 1
processor	: 2
model name	: Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz
physical id	: 2
processor	: 3
model name	: Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz
physical id	: 3
processor	: 4
model name	: Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz
physical id	: 4
processor	: 5
model name	: Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz
physical id	: 5
processor	: 6
model name	: Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz
physical id	: 6
processor	: 7
model name	: Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz
physical id	: 7
</pre>
<p>只是容器内核对文件系统的支持比较坑爹：</p>
<pre class="brush: bash; title: ; notranslate">
root@837bc28c1c36:~# cat /proc/filesystems
nodev	sysfs
nodev	rootfs
nodev	tmpfs
nodev	bdev
nodev	proc
nodev	cpuset
nodev	cgroup
nodev	cgroup2
nodev	devtmpfs
nodev	debugfs
nodev	tracefs
nodev	securityfs
nodev	sockfs
nodev	bpf
nodev	pipefs
nodev	ramfs
nodev	hugetlbfs
nodev	devpts
nodev	pstore
nodev	mqueue
nodev	selinuxfs
nodev	autofs
	squashfs
	iso9660
	ext3
	ext2
	ext4
nodev	overlay
</pre>
<p>不支持 NFS 挂载远程目录，也不支持 FUSE 用户层文件系统来实现挂载 Amazon S3 存储之类的，这对于目前还不支持外部存储的 Arukas 容器来说实在不算友好。</p>
<h2 id="use-shadowsocks-container">使用 Shadowsocks 容器</h2>
<h3 id="shadowsocks-speed">Shadowsocks 效果</h3>
<p>客户端使用上面指定的 Shadowsocks 服务器配置就可以爬墙上网了，当然使用前需要将 Shadowsocks 服务器地址更换为 Arukas 容器的临时域名，并将服务器端口改为当前映射出来的外部端口（不能直接使用内部端口）。</p>
<p>这个是我在宿舍江苏移动宽带网络下观看 Youtube 1080p 视频的效果，8 Mbps 的速度看起来还是比较给力的：</p>
<p><img src="http://res.cloudinary.com/digwht2y0/image/upload/v1737370582/arukas-ss-speed.png" alt="Arukas Shadowsocks 速度" title="Arukas Shadowsocks 速度"></p>
<p>换到南京电信网络进行路由追踪，可以看到 ping 值还不到 50 ms：</p>
<p><img src="http://res.cloudinary.com/digwht2y0/image/upload/v1737370582/arukas-ip-route.png" alt="Arukas 容器路由追踪" title="Arukas 容器路由追踪" width="640" height="526"></p>
<h3 id="openwrt-shadowsocks-script">OpenWRT 自动更新 Shadowsocks 配置</h3>
<p>由于 Arukas 容器的外网地址和端口在每次启动时都不是固定的，容器重启后 Shadowsocks 客户端都需要获取当前临时域名和外部端口，这样用起来还是不太方便。特别对于我这种需要 OpenWRT 路由器直接翻墙的用户来说，每次修改 OpenWRT 设置就太麻烦了。</p>
<p>好消息就是 Arukas 容器的 Endpoint 地址还是固定的，我写的启动脚本也自动将容器当前的临时域名、公网 IP 地址、所有外部端口都输出到文件了，可以直接通过 Endpoint 地址访问。</p>
<p>因此我又专门写了一个适用于 OpenWRT 系统的更新 Arukas 容器配置的脚本：<code>arukas-ss.sh</code>，可添加到路由器的 Shadowsocks 服务脚本中，也可以设置成定时任务：</p>
<pre class="brush: bash; title: ; notranslate">
#!/bin/sh
[ $# -ge 2 ] || exit 1

[ -f /tmp/.marathon.conf ] &amp;&amp; mv /tmp/.marathon.conf /tmp/.marathon.conf.bak

IND=0
while [ $IND -lt 20 ]; do
	let IND++
	[ -f /tmp/.marathon.conf ] &amp;&amp; rm -f /tmp/.marathon.conf
	curl -s -k -f -o /tmp/.marathon.conf https://zohead-server.arukascloud.io/marathon.conf
	[ $? -eq 0 ] &amp;&amp; break
	sleep 1
done

[ -s /tmp/.marathon.conf ] || exit 1
echo &quot;Fetch server config after $IND tries.&quot;

if [ -f /tmp/.marathon.conf.bak ]; then
	cmp -s /tmp/.marathon.conf /tmp/.marathon.conf.bak
	if [ $? -eq 0 ]; then
		rm -f /tmp/.marathon.conf
		exit 0
	fi
fi

. /tmp/.marathon.conf 2&gt;/dev/null
if [ &quot;x$MARATHON_HOST&quot; = &quot;x&quot; ]; then
	rm -f /tmp/.marathon.conf
	exit 1
fi

while [ $# -gt 1 ]; do
	CMD=&quot;echo \${MARATHON_PORT_$2}&quot;
	SS_PORT=`eval $CMD`

	if [ -f $1 -a &quot;x$SS_PORT&quot; != &quot;x&quot; ]; then
		if [ &quot;x$MARATHON_HOST_IP&quot; != &quot;x&quot; ]; then
			MARATHON_HOST=&quot;$MARATHON_HOST_IP&quot;
		fi
		sed -i -e 's/&quot;server&quot;[^:]*:[^,]*,/&quot;server&quot; : &quot;'$MARATHON_HOST'&quot;,/' -e 's/&quot;server_port&quot;[^:]*:[^,]*,/&quot;server_port&quot; : &quot;'$SS_PORT'&quot;,/' $1
		SS_PID=`pgrep -f &quot;ss-redir -c $1&quot;`
		if [ $? -eq 0 ]; then
			kill $SS_PID &gt;/dev/null 2&gt;&amp;1
			kill -9 $SS_PID &gt;/dev/null 2&gt;&amp;1
			start-stop-daemon -x /usr/bin/ss-redir -b -S -- -c $1 -b 0.0.0.0
		fi
	fi
	shift
	shift
done
</pre>
<p><code>arukas-ss.sh</code> 脚本的使用方法为：</p>
<pre class="brush: bash; title: ; notranslate">
arukas-ss.sh shadowsocks-1.json 17374 shadowsocks-2.json 2233 ... ...
</pre>
<p>第一个参数为 Shadowsocks 客户端 JSON 配置文件的完整路径，第二个参数为该文件对应的 Arukas Shadowsocks 服务器配置的内部监听端口号，<code>arukas-ss.sh</code> 脚本支持多个本地 Shadowsocks 配置文件和服务器内部监听端口号，依次类推即可。</p>
<p>使用前需要替换 <code>arukas-ss.sh</code> 脚本中的 Endpoint 地址，考虑到 Arukas 容器目前的 Endpoint 访问还不太稳定的情况，脚本里也加了多次访问尝试，我的 Endpoint 地址是这样：</p>
<pre class="brush: plain; title: ; notranslate">

https://zohead-server.arukascloud.io/marathon.conf

</pre>
<p>另外可以修改 OpenWRT 的定时任务配置实现自动更新，例如在 <code>/etc/crontabs/root</code> 文件中增加一行：</p>
<pre class="brush: plain; title: ; notranslate">
30 * * * * /etc/arukas-ss.sh /etc/shadowsocks.json 17374
</pre>
<p>这就表示在每个小时的第 30 分钟执行 <code>arukas-ss.sh</code> 脚本更新 Arukas Shadowsocks 配置，一般这样就能对付 Arukas 容器每隔几个小时自动重启的问题了。</p>
<h2 id="postscript">后记</h2>
<p>经过我这段时间的试用，Arukas 容器做为爬墙服务器还是比较顺畅的，如果想捣鼓一个简单的 API 服务器也还凑合，不过由于 Arukas 目前还不支持外部存储，想拿来跑个博客程序之类的就要涉及到如何保存和恢复网站数据的问题了。</p>
<p>当然容器只能用 Endpoint 地址访问也是一个大问题，经过测试我也发现如果容器内开放的内部端口稍微一多（可能超过 3 个）时，Arukas 的 HAProxy 转发服务就不太稳定了，经常出现 502 或者 503 错误。如果容器内开放了 UDP 端口，Endpoint 地址甚至可能会处于一直都不能访问的状况。</p>
<p>如果 Arukas 容器在内测期间能解决这些问题，后续正式使用价格也不算离谱的话，感觉应该还是有些竞争力的，最后祝大家 4 月玩的开心。</p>
]]></content:encoded>
			<wfw:commentRss>https://zohead.com/archives/arukas-container/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
	</channel>
</rss>
