diff --git a/404.md b/404.md
index 1cea9647e8e25..ce124b556134e 100644
--- a/404.md
+++ b/404.md
@@ -1,8 +1,5 @@
---
layout: page
-title: 404 - Page not found
+title: 404 - 我猜你迷路了!没找到你想要的。
---
-
-Sorry, we can't find that page that you're looking for. You can try take for a look by going [back to the homepage]({{ site.baseurl }}/).
-
-[
]({{ site.baseurl }}/)
\ No newline at end of file
+
diff --git a/CNAME b/CNAME
index 8b137891791fe..833868e549d06 100644
--- a/CNAME
+++ b/CNAME
@@ -1 +1 @@
-
+jeffkit.com
diff --git a/_config.yml b/_config.yml
index 494da8c24deec..1672102f41af8 100644
--- a/_config.yml
+++ b/_config.yml
@@ -3,13 +3,13 @@
#
# Name of your site (displayed in the header)
-name: Your Name
+name: Jeff的妙想奇境
# Short bio or description (displayed in the header)
-description: Web Developer from Somewhere
+description: 告诉你,她来自我的心
# URL of your avatar or profile pic (you could use your GitHub profile pic)
-avatar: https://raw.githubusercontent.com/barryclark/jekyll-now/master/images/jekyll-logo.png
+avatar: https://avatars3.githubusercontent.com/u/252377?v=3&s=460
#
# Flags below are optional
@@ -18,15 +18,15 @@ avatar: https://raw.githubusercontent.com/barryclark/jekyll-now/master/images/je
# Includes an icon in the footer for each username you enter
footer-links:
dribbble:
- email:
- facebook:
+ email: bbmyth+pages@gmail.com
+ facebook: i.jeff.kit
flickr:
- github: barryclark/jekyll-now
+ github: jeffkit
instagram:
linkedin:
pinterest:
rss: # just type anything here for a working RSS icon, make sure you set the "url" above!
- twitter: jekyllrb
+ twitter: jeff_kit
stackoverflow: # your stackoverflow profile, e.g. "users/50476/bart-kiers"
youtube: # channel/ or user/
@@ -39,7 +39,7 @@ google_analytics:
# Your website URL (e.g. http://barryclark.github.io or http://www.barryclark.co)
# Used for Sitemap.xml and your RSS feed
-url:
+url: http://jeffkit.com
# If you're hosting your site at a Project repository on GitHub pages
# (http://yourusername.github.io/repository-name)
diff --git a/_posts/2014-3-3-Hello-World.md b/_posts/2014-3-3-Hello-World.md
deleted file mode 100644
index d4665b6d18e9e..0000000000000
--- a/_posts/2014-3-3-Hello-World.md
+++ /dev/null
@@ -1,10 +0,0 @@
----
-layout: post
-title: You're up and running!
----
-
-Next you can update your site name, avatar and other options using the _config.yml file in the root of your repository (shown below).
-
-
-
-The easiest way to make your first post is to edit this one. Go into /_posts/ and update the Hello World markdown file. For more instructions head over to the [Jekyll Now repository](https://github.com/barryclark/jekyll-now) on GitHub.
\ No newline at end of file
diff --git a/_posts/2015-3-11-Hello-World.md b/_posts/2015-3-11-Hello-World.md
new file mode 100644
index 0000000000000..5eff802ad5a12
--- /dev/null
+++ b/_posts/2015-3-11-Hello-World.md
@@ -0,0 +1,12 @@
+---
+layout: post
+title: 我回来了
+---
+
+
+
+Hi,我是Jeff,我回来了。
+
+创业三年多,一直在所谓的碎片化里生存,刷微博、刷微信、刷知乎等等,整个人都碎了,有深深有无力感。写文章也许是把破碎的我重新拼装回来的唯一有效途径吧。
+
+三年多的时间里面,发生过很多事情,将来,还有更有趣的事情发生,容我好好坐下来,慢慢讲。谢谢!
\ No newline at end of file
diff --git a/_posts/2015-3-23-os-vs-app.md b/_posts/2015-3-23-os-vs-app.md
new file mode 100644
index 0000000000000..04f2c6209d003
--- /dev/null
+++ b/_posts/2015-3-23-os-vs-app.md
@@ -0,0 +1,29 @@
+---
+layout: post
+title: 写操作系统就比写App牛B吗
+---
+
+
+
+今天中午在办公室和同事喝茶聊(chui)人(niu)生(bi)的时候,提到已离职的某前同事,同时想起当时离职的其中一个原因,有感,遂记录之,同时献给一直在认为自己做的事情无足轻重或无存在感的同学。
+
+这位旧同事,他曾经跟我抱怨过自己整天在写业务代码,没有更大的发展空间,是他想要离职的原因之一。我问,什么叫写业务代码,他说,就是写应用业务逻辑啊,不像你,可以设计公司的技术架构,多牛B。我笑着说,那我也是在写业务代码啊,只不过我面向的用户是公司的开发同学,业务是让大家写代码和运维起来更爽更快而已。
+
+应该有不少同学都会认为,写操作系统的人一定比写app的人要牛B。并由此推理,架构师一定比研发牛B,研发一定比开发牛B。如果你也这么认为,那你就错了,掉进了一个看上去是正确的坑里。
+
+事实上,不管是写操作系统还是写一个应用,本质上都是在解决具体的业务问题,要求工程师们首先要对业务知识了如指掌,再通过工程的方法来解决它,过程是统一无异的。
+
+例如同样是写操作系统,有些人写的水平就是跟着《自制操作系统》做出来的差不多,而有人则写出了世界上最流行的操作系统之一,指的是linus。
+例如同样是写app,你可能写的乱七八糟crash不断,但高手写出来的作品就行云流水,体验满分呢。
+
+有同学也许会反驳:胡说!写操作系统用的技术哪里是你做应用能用得上的呢!呵呵!那我只能说,如果你的操作系统只是一个简单的Demo,我打赌,它一定没有你正在写的app用到的算法、技术点多。
+
+当然,我的意思并不是说你现在是个初级开发者,一样可以做好与架构师同样的事情。架构师的业务知识的积累是来自具体的应用开发生涯,也就是说没有一定的应用开发经验的(业务知识)积累,是干不好(不是干不了)架构师干的事的。
+
+所以,写操作系统的人未必比写App的人牛B!你如果认为自己做的事情无足轻重,没有存在感,问题的根本不在于你正在做的事情,而在于你没有把它做好。做不好,你只会让自己长期处于这种被动的局面,就算你换份工作亦然;做好了,后续的好事情才会继续来,改变才会真正发生。
+
+所以,看见脏代码,很不爽,你要干的事情是捋干净它,而不是坐着叹前任不行又沿他步履前行;感觉天天在做重复的事情,那就让它自动化,而不是机械般地复制粘贴;把你讨厌的事情都干掉,很快你就无事可干了,即有更重要的事情可以干了!
+
+人的竟争力不在于你在做什么,而在于那件事情你做得比其他人好。
+
+就酱!
\ No newline at end of file
diff --git a/_posts/2015-4-16-dokku.md b/_posts/2015-4-16-dokku.md
new file mode 100644
index 0000000000000..7c8d00b5430be
--- /dev/null
+++ b/_posts/2015-4-16-dokku.md
@@ -0,0 +1,351 @@
+---
+layout: post
+title: Dokku自动部署源码解读
+---
+
+Dokku是一个号称世界上最小的PAAS平台,百行级别的代码实现单机版的Heroku。读一下它的源码看看他到底做了些什么事情。
+
+关于Dokku怎么安装和使用,并不是本文关注的范围,如果你还没用过Dokku,建议先补补课。
+
+另,本文只关心Dokku的自动部署部份的代码,其他命令行的代码不在本文解读。
+
+##魔术发生的地方
+
+当你在本地向Dokku的服务器推送最新的代码时,Dokku会为你接管以下工作:
+
+- 检查你的代码类型,编译之。
+- 使用Docker运行你的应用,并将其暴露在外网。
+
+那么,我们读源码就从这里开始吧,假如我们的项目名是helloworld,当你向dokku的git推送代码时,会触发Git的hooks脚本,Dokku仅提供了一个脚本:pre-receive:
+
+```
+$ cat /home/dokku/helloworld/hooks/pre-receive
+#!/usr/bin/env bash
+set -e; set -o pipefail;
+
+cat | DOKKU_ROOT="/home/dokku" dokku git-hook helloworld
+```
+
+关键的命令是```dokku git-hook helloworld```,我们需要去阅读dokku脚本来了解更多了!
+
+### Dokku git-hook
+Dokku所有代码都是shell脚本,Dokku主代码的结构大致如下:
+
+- 声明变量
+- 加载通用的函数,如log,parse_args等。
+- 执行用户定义脚本 $DOKKU_ROOT/dokkurc或 $DOKKU_ROOT/.dokkurc目录下的脚本。
+- 执行用户指定的命令,DOKKU主脚本仅声明了几个命令:receive, deploy, cleanup, plugins, plugins-install, plugins-install-depencdencies, plugin-update, deploy:all, help。如果主脚本找不到命令,则会去插件目录查找是否存在,在则执行插件的命令。
+
+
+### git-hook
+
+git-hook这个命令,是在plugins/git/commands里面定义的:
+
+```
+case "$1" in
+ git-hook)
+ APP=$2
+
+ while read oldrev newrev refname
+ do
+ # Only run this script for the master branch. You can remove this
+ # if block if you wish to run it for others as well.
+ if [[ $refname = "refs/heads/master" ]] ; then
+ # broken out into pluginhook so we might support other methods to receive an app
+ pluginhook receive-app $APP $newrev
+ else
+ echo $'\e[1G\e[K'"-----> WARNING: deploy did not complete, you must push to master."
+ echo $'\e[1G\e[K'"-----> for example, try 'git push ${refname/refs\/heads\/}:master'"
+ fi
+ done
+ ;;
+```
+程序从命令行中读取参数,判断所更新的分支是否master分支,不接受非master分支的推送。
+正常的推送,会继续调用```pluginhook receive-app $APP $newrev```这个命令。
+
+### receive-app
+
+pluginhook是Dokku作者的另一个开源项目,是用来方便执行分散在某个目录下的命令的。
+我们在plugins/git的目录下找下receive-app这个脚本:
+
+```
+#!/usr/bin/env bash
+set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
+source "$(dirname $0)/../common/functions"
+
+APP="$1"; REV="$2"
+
+dokku git-build $APP $REV
+```
+
+好吧,又跳转到git-build去了。
+
+### git-build
+
+在plugins/git/commands脚本下面找到git-build命令:
+
+```
+git-build)
+ APP="$2"; APP_BUILD_LOCK="$DOKKU_ROOT/$APP/.build.lock"
+ APP_BUILD_LOCK_MSG="$APP is currently being deployed or locked. Waiting..."
+ [[ $(flock -n "$APP_BUILD_LOCK" true &>/dev/null ; echo $?) -ne 0 ]] && echo "$APP_BUILD_LOCK_MSG"
+
+ shift 1
+ flock -o "$APP_BUILD_LOCK" dokku git-build-locked "$@"
+ ;;
+
+```
+检测当前是否正在build,如果正在build,则提示等待下一次。否则创建一个锁,开始build。调用 ```dokku git-build-locked```
+
+### git-build-locked
+
+```
+git_build_app_repo() {
+ verify_app_name "$1"
+ APP="$1"; REV="$2"
+
+ # clean up after ourselves
+ TMP_WORK_DIR=$(mktemp -d)
+ trap 'rm -rf "$TMP_WORK_DIR" > /dev/null' RETURN
+
+ # git clone
+ chmod 755 $TMP_WORK_DIR
+ unset GIT_DIR GIT_WORK_TREE
+ pushd $TMP_WORK_DIR > /dev/null
+ git clone -q "$DOKKU_ROOT/$APP" "$TMP_WORK_DIR" &> /dev/null
+ git config advice.detachedHead false
+ git checkout "$REV" &> /dev/null
+ git submodule update --init --recursive &> /dev/null
+ find -name .git -prune -exec rm -rf {} \; > /dev/null
+
+ if [[ -f Dockerfile ]] && [[ "$([[ -f .env ]] && grep -q BUILDPACK_URL .env; echo $?)" != "0" ]] && [[ ! -f ".buildpacks" ]]; then
+ dokku receive "$APP" "dockerfile" "$TMP_WORK_DIR" | sed -u "s/^/"$'\e[1G'"/"
+ else
+ dokku receive "$APP" "buildstep" "$TMP_WORK_DIR" | sed -u "s/^/"$'\e[1G'"/"
+ fi
+}
+
+ git-build-locked)
+ APP="$2"
+ if [[ $# -ge 3 ]];then
+ REF="$3"
+ else
+ REF=$(< "$DOKKU_ROOT/$APP/refs/heads/master")
+ fi
+ git_build_app_repo $APP $REF
+ ;;
+```
+这里做的事情就是创建一个临时目录,把应用的源码clone出来,再检查看看是使用DockerFile构建还是buildstep构建,然后分别使用不同的方式来构建之。完事后把临时目录删除。
+
+下面是关键的步骤 ```dokku receive "$APP" "buildstep" "$TMP_WORK_DIR" | sed -u "s/^/"$'\e[1G'"/"```
+
+### receive
+receive命令定义在dokku主文件:
+
+```
+receive)
+ APP="$2"; IMAGE="dokku/$APP"; IMAGE_SOURCE_TYPE="$3"; TMP_WORK_DIR="$4"
+ dokku_log_info1 "Cleaning up..."
+ dokku cleanup
+ dokku_log_info1 "Building $APP from $IMAGE_SOURCE_TYPE..."
+ dokku build "$APP" "$IMAGE_SOURCE_TYPE" "$TMP_WORK_DIR"
+ dokku_log_info1 "Releasing $APP..."
+ dokku release "$APP" "$IMAGE_SOURCE_TYPE"
+ dokku_log_info1 "Deploying $APP..."
+ dokku deploy "$APP"
+ dokku_log_info2 "Application deployed:"
+ dokku urls "$APP" | sed "s/^/ /"
+ echo
+ ;;
+```
+可以看到,收到推送后的构建过程有以下几步:
+
+- cleanup, 清除掉所有未运行的容器及未使用的镜像。
+- build, 构建
+- release, 发布新版本
+- deploy, 部署
+
+#### build
+在plugins/00_dokku-standard/commands中找到build命令的定义:
+
+```
+case "$1" in
+ build)
+ APP="$2"; IMAGE="dokku/$APP"; IMAGE_SOURCE_TYPE="$3"; TMP_WORK_DIR="$4"
+ CACHE_DIR="$DOKKU_ROOT/$APP/cache"
+
+ pushd "$TMP_WORK_DIR" &> /dev/null
+
+ case "$IMAGE_SOURCE_TYPE" in
+ buildstep)
+ id=$(tar -c . | docker run -i -a stdin $DOKKU_IMAGE /bin/bash -c "mkdir -p /app && tar -xC /app")
+ test "$(docker wait $id)" -eq 0
+ docker commit $id $IMAGE > /dev/null
+ [[ -d $CACHE_DIR ]] || mkdir $CACHE_DIR
+ # *DEPRECATED* in v0.4.0: `pluginhook pre-build` will be removed in future releases
+ pluginhook pre-build "$APP"
+ pluginhook pre-build-buildstep "$APP"
+
+ # *DEPRECATED* in v0.3.14: `pluginhook docker-args` will be removed in future releases
+ # https://github.com/progrium/dokku/issues/896 & https://github.com/progrium/dokku/issues/906
+ DOCKER_ARGS=$(: | pluginhook docker-args $APP build)
+ DOCKER_ARGS+=$(: | pluginhook docker-args-build $APP)
+ id=$(docker run -d -v $CACHE_DIR:/cache -e CACHE_PATH=/cache $DOCKER_ARGS $IMAGE /build/builder)
+ docker attach $id
+ test "$(docker wait $id)" -eq 0
+ docker commit $id $IMAGE > /dev/null
+
+ # *DEPRECATED* in v0.4.0: `pluginhook post-build` will be removed in future releases
+ pluginhook post-build "$APP"
+ pluginhook post-build-buildstep "$APP"
+ ;;
+
+ dockerfile)
+ # extract first port from Dockerfile
+ DOCKERFILE_PORT=$(grep EXPOSE Dockerfile | head -1 | awk '{ print $2 }' || true)
+ [[ -n "$DOCKERFILE_PORT" ]] && dokku config:set-norestart $APP DOKKU_DOCKERFILE_PORT=$DOCKERFILE_PORT
+
+ # buildstep pluginhooks don't necessarily make sense for dockerfiles. call the new breed!!!
+ pluginhook pre-build-dockerfile "$APP"
+
+ docker build -t "$IMAGE" .
+
+ pluginhook post-build-dockerfile "$APP"
+ ;;
+
+ *)
+ dokku_log_fail "Building image source type $IMAGE_SOURCE_TYPE not supported!"
+ ;;
+ esac
+ ;;
+```
+在BuildStep类型的应用当中,关键的一行代码在这里:
+
+```
+id=$(docker run -d -v $CACHE_DIR:/cache -e CACHE_PATH=/cache $DOCKER_ARGS $IMAGE /build/builder)
+```
+
+关键的Build脚本在buildstep镜像的/build/builder里面。这个脚本将在被执行完之后删除,所以在app的镜像中是找不到它的存在的。
+
+build目录的结构如下:
+
+```
+builder
+complie.sh
+install-buildpack
+config
+ - buildpacks
+ - paths.sh
+```
+
+##### builder
+
+下面先来看看build脚本做了什么事。这是整个Dokku当中最关键的一步!builder脚本主要做了以下事情:
+
+- 创建一系列的目录备用。
+- 创建一个随机用户,并让该用户有权限访问上面的目录。
+- 调用同目录下的compile.sh脚本,这才是真正构建应用的地方。
+- 生成一个start脚到到根目录下。用于启动应用。
+
+##### complile.sh
+
+compile.sh脚本,也就是整个Build过程最核心的环节,使用buildpack来检测应用的类型并使用对应的buildpack来compile, release个应用。
+
+整个Build过程到此完毕。
+
+#### Release
+
+应用创建好以后,就应该release.再次回到Dokku脚本的receive部份,跟踪dokku release。在plugins/00_dokku-standard的commands脚本上找到release部份:
+
+```
+if [[ -f "$DOKKU_ROOT/ENV" ]]; then
+ id=$(docker run -i -a stdin $IMAGE /bin/bash -c "mkdir -p /app/.profile.d && cat > /app/.profile.d/00-global-env.sh" < "$DOKKU_ROOT/ENV")
+ test "$(docker wait $id)" -eq 0
+ docker commit $id $IMAGE > /dev/null
+ fi
+ if [[ -f "$DOKKU_ROOT/$APP/ENV" ]]; then
+ id=$(docker run -i -a stdin $IMAGE /bin/bash -c "mkdir -p /app/.profile.d && cat > /app/.profile.d/01-app-env.sh" < "$DOKKU_ROOT/$APP/ENV")
+ test "$(docker wait $id)" -eq 0
+ docker commit $id $IMAGE > /dev/null
+```
+关键的操作是把两个文件复制到镜像的/app/.profile.d/目录下面:
+
+- $DOKKU_ROOT/ENV
+- $DOKKU_ROOT/$APP/ENV
+
+这两个文件其实都是用户定义的环境变量来的。
+
+#### Deploy
+
+deploy部分的代码位于dokku主脚本内:
+
+```
+deploy)
+ APP="$2"; IMAGE="dokku/$APP"
+ pluginhook pre-deploy $APP
+
+ if [[ -f "$DOKKU_ROOT/$APP/CONTAINER" ]]; then
+ oldid=$(< "$DOKKU_ROOT/$APP/CONTAINER")
+ fi
+
+ # start the app
+ DOCKER_ARGS=$(: | pluginhook docker-args $APP deploy)
+ DOCKER_ARGS+=$(: | pluginhook docker-args-deploy $APP)
+ BIND_EXTERNAL=$(pluginhook bind-external-ip $APP)
+
+ is_image_buildstep_based "$IMAGE" && DOKKU_BUILDSTEP=true
+ [[ -n "$DOKKU_BUILDSTEP" ]] && START_CMD="/start web"
+ [[ -z "$DOKKU_BUILDSTEP" ]] && DOKKU_DOCKERFILE_PORT=$(dokku config:get $APP DOKKU_DOCKERFILE_PORT || true)
+
+ if [[ "$BIND_EXTERNAL" = "false" ]];then
+ port=${DOKKU_DOCKERFILE_PORT:=5000}
+ id=$(docker run -d -e PORT=$port $DOCKER_ARGS $IMAGE $START_CMD)
+ ipaddr=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' $id)
+ else
+ id=$(docker run -d -p 5000 -e PORT=5000 $DOCKER_ARGS $IMAGE $START_CMD)
+ port=$(docker port $id 5000 | sed 's/[0-9.]*://')
+ ipaddr=127.0.0.1
+ fi
+
+ # if we can't post-deploy successfully, kill new container
+ kill_new() {
+ docker inspect $id &> /dev/null && docker kill $id > /dev/null
+ trap - INT TERM EXIT
+ kill -9 $$
+ }
+
+ # run checks first, then post-deploy hooks, which switches Nginx traffic
+ trap kill_new INT TERM EXIT
+ dokku_log_info1 "Running pre-flight checks"
+ pluginhook check-deploy $APP $port $ipaddr $id
+ trap - INT TERM EXIT
+
+ # now using the new container
+ echo $id > "$DOKKU_ROOT/$APP/CONTAINER"
+ echo $ipaddr > "$DOKKU_ROOT/$APP/IP"
+ echo $port > "$DOKKU_ROOT/$APP/PORT"
+ echo "http://$(< "$DOKKU_ROOT/HOSTNAME"):$port" > "$DOKKU_ROOT/$APP/URL"
+
+ dokku_log_info1 "Running post-deploy"
+ pluginhook post-deploy $APP $port $ipaddr
+
+ # kill the old container
+ if [[ -n "$oldid" ]]; then
+ # Let the old container finish processing requests, before terminating it
+ WAIT="${DOKKU_WAIT_TO_RETIRE:-60}"
+ dokku_log_info1 "Shutting down old container in $WAIT seconds"
+ (
+ exec >/dev/null 2>/dev/null {{ post.title }}
Read More
{% endfor %}
-
\ No newline at end of file
+