diff --git "a/blog-cn/\345\257\214\345\256\271\345\231\250\346\212\200\346\234\257.md" "b/blog-cn/\345\257\214\345\256\271\345\231\250\346\212\200\346\234\257.md"
new file mode 100644
index 0000000..c94e467
--- /dev/null
+++ "b/blog-cn/\345\257\214\345\256\271\345\231\250\346\212\200\346\234\257.md"
@@ -0,0 +1,131 @@
+# 富容器技术
+
+当容器化应用程序时,富容器是一种非常有用的容器模式。此模式可帮助技术人员几乎毫不费力地打包粗壮应用程序。它提供了有效的方法来装备更多基本软件或系统服务除了目标应用程序在单个容器中。然后,容器中的应用程序可以像通常在虚拟机或物理机中一样平滑运行。这是一种更通用的以应用程序为中心的模式,该模式对开发人员和运营商都没有任何侵略性。特别是对于运营商而言,他们可以像往常一样使用他们可能需要的所有必要工具或服务流程来维护容器中的应用程序。
+
+PouchContainer 提供的富容器模式不是默认模式。拓展用户的容器体验是 PouchContainer 带来的一种额外模式。用户仍然可以通过关闭富容器标志来管理普通容器。
+
+总之,富容器可以帮助企业实现以下两个目标:
+
+* 与传统操作系统兼容;
+* 仍然利用镜像概念的优势来加快应用程序交互。
+
+## 脚本
+
+容器技术和编排平台现在变得非常流行。它们都为应用程序提供了更好的环境。尽管如此,我们不得不说容器化是企业采用容器相关技术的第一步,例如容器,编排,服务网等。将传统应用程序转移到容器中是一个非常实际的问题。虽然一些简单的应用程序总是对容器显示友好,但更传统和复杂的企业应用程序可能不那么幸运。这些传统应用程序通常与底层基础架构相耦合,例如机器架构,旧内核,甚至某些软件也不需要维护。当然,强耦合不是每个人的菜。它是企业数字化转型之路的发起者。因此,所有行业都在寻求一种可行的方法来解决这个问题。 docker提供的方式是一种,但不是最好的。在过去的7年里,阿里巴巴也遇到了同样的问题。幸运的是,富容器模式是一种更好的处理方式。
+
+开发人员有自己的编程风格。他们的工作是创建有用的应用程序,而不是设计绝对解耦的应用程序,因此他们通常利用工具或系统服务来实现它。当容器化这些应用程序时,如果仅在容器中设置一个应用程序一个进程,则相当薄弱。富容器模式找出了使用户在容器中配置进程的内部启动顺序的方法,包括应用程序和系统服务。
+
+运营商富有保护应用程序正常运行的神圣职责。为了使业务在应用程序中运行,技术必须充分尊重运营商的传统。在线调试和解决问题时,环境变化不是一个好消息。富容器模式可以确保富容器中的环境与传统VM或物理机中的环境完全相同。如果操作员需要一些系统工具,它们仍然定位于那里。如果某些前后挂钩应该生效,只需在启动富容器时设置它们即可。 如果内部发生了一些问题,富容器启动的系统服务可以像自我修复一样修复它们。
+
+## 架构
+
+富容器模式与运营团队的传统操作方式兼容。 以下架构图显示了如何实现:
+
+![pouch_with_rich_container](https://github.com/alibaba/pouch/blob/master/docs/static_files/pouch_with_rich_container.png)
+
+更详细的说,富容器承诺与oci适配镜像兼容。在运行富容器时,pouchd 会将镜像文件系统作为富容器本身的根文件系统。在内部容器的运行时,除了内部应用程序和系统服务之外,还有一些hook如prestart hook 和 poststop hook。前者重点在于如何在 systmed 和相关进程运行之前准备或初始化环境。后者主要是当容器停止时进行清理工作。
+
+## 启动
+
+用户可以很容易地在 PouchContainer 中启动富容器模式。 如果我们需要通过 PouchContainer 在富容器模式下运行普通镜像,我们可以添加两个标志:`--rich`,`--rich-mode`和 `--initscript`。 以下是关于这两个标志的更多描述:
+
+* `--rich`:标识是否打开富容器模式。此标志的类型为`boolean`,默认值为`false`。
+
+* `--rich-mode`:选择初始化容器的方式,当前支持 systemd,/ sbin / init 和 dumb-init 的方式。默认情况下是 dumb-init。
+
+* `--initscript`:标识在容器中执行的初始脚本。该脚本将在入口点或命令之前执行。有时,它被称为 prestart hook。在 prestart hook 中可以做很多工作,例如环境检查,环境准备,网络路由准备,各种代理设置,安全设置等。如果 pouchd 无法在由从镜像和实际位于容器外部的潜在挂载卷提供的容器文件系统中找到此 initscript 标志,则该脚本可能会失败并且用户会收到相关的错误消息。如果 initscript 正常工作,容器进程的控制将由进程 pid 1接管,主要是`/ sbin / init`或`dumbinit`。
+
+
+
+事实上,PouchContainer 团队计划添加另一个标志`--initcmd`以使用户输入 prestart hook。实际上它是`--initscript`的简化版。同时它比`--initscript`更便捷。 `--initcmd`可以根据用户的意愿设置任何命令,并且不需要事先将其放置在镜像中。可以说实现了命令与镜像解耦。但是对于`--initscript`,脚本文件必须首先位于镜像中,这是某种耦合。
+
+如果用户指定`--rich`标志并且未提供`--initscript`标志,则仍将启用富容器模式,但不会执行initscript。 如果`--rich`标志在命令行中丢失,而`--initscript`存在,PouchContainer CLI 或Pouchd 将返回错误以显示`--initscipt`只能与`--rich`标志一起使用。
+
+如果容器正在运行`--rich`标志,那么每次启动或重启此容器都会触发相应的 initscipt。
+
+### 使用 dumb-init
+
+以下是富容器模式的使用 dumb-init 来初始化容器的简单示例:
+
+1.按如下步骤安装 dumb-init:
+
+```shell
+# wget -O /usr/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v1.2.1/dumb-init_1.2.1_amd64
+# chmod +x /usr/bin/dumb-init
+```
+
+2.运行富模式的容器:
+
+ ```shell
+#pouch run -d --rich --rich-mode dumb-init registry.hub.docker.com/library/busybox:latest sleep 10000
+f76ac1e49e9407caf5ad33c8988b44ff3690c12aa98f7faf690545b16f2a5cbd
+
+#pouch exec f76ac1e49e9407caf5ad33c8988b44ff3690c12aa98f7faf690545b16f2a5cbd ps -ef
+PID USER TIME COMMAND
+1 root 0:00 /usr/bin/dumb-init -- sleep 10000
+7 root 0:00 sleep 10000
+8 root 0:00 ps -ef
+ ```
+
+### 使用 systemd 或 sbin-init
+
+为了使用systemd或/ sbin / init初始化容器,请确保将它们安装在镜像文件上。
+
+如下图所示,centos镜像两者都有。
+
+此外,在这种情况下需要`--privileged` 。 systemd 和 sbin-init的示例如下:
+
+```
+#cat /tmp/1.sh
+#! /bin/sh
+echo $(cat) >/tmp/xxx
+
+#pouch run -d -v /tmp:/tmp --privileged --rich --rich-mode systemd --initscript /tmp/1.sh registry.hub.docker.com/library/centos:latest /usr/bin/sleep 10000
+3054125e44443fd5ee9190ee49bbca0a842724f5305cb05df49f84fd7c901d63
+
+#pouch exec 3054125e44443fd5ee9190ee49bbca0a842724f5305cb05df49f84fd7c901d63 ps aux
+USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
+root 1 7.4 0.0 42968 3264 ? Ss 05:29 0:00 /usr/lib/systemd/systemd
+root 17 0.0 0.0 10752 756 ? Ss 05:29 0:00 /usr/lib/systemd/systemd-readahead collect
+root 18 3.2 0.0 32740 2908 ? Ss 05:29 0:00 /usr/lib/systemd/systemd-journald
+root 34 0.0 0.0 22084 1456 ? Ss 05:29 0:00 /usr/lib/systemd/systemd-logind
+root 36 0.0 0.0 7724 608 ? Ss 05:29 0:00 /usr/bin/sleep 10000
+dbus 37 0.0 0.0 24288 1604 ? Ss 05:29 0:00 /bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation
+root 45 0.0 0.0 47452 1676 ? Rs 05:29 0:00 ps aux
+
+#cat /tmp/xxx
+{"ociVersion":"1.0.0","id":"3054125e44443fd5ee9190ee49bbca0a842724f5305cb05df49f84fd7c901d63","status":"","pid":125745,"bundle":"/var/lib/pouch/containerd/state/io.containerd.runtime.v1.linux/default/3054125e44443fd5ee9190ee49bbca0a842724f5305cb05df49f84fd7c901d63"}
+
+#pouch run -d -v /tmp:/tmp --privileged --rich --rich-mode sbin-init --initscript /tmp/1.sh registry.hub.docker.com/library/centos:latest /usr/bin/sleep 10000
+c5b5eef81749ce00fb68a59ee623777bfecc8e07c617c0601cc56e4ae8b1e69f
+
+#pouch exec c5b5eef81749ce00fb68a59ee623777bfecc8e07c617c0601cc56e4ae8b1e69f ps aux
+USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
+root 1 7.4 0.0 42968 3260 ? Ss 05:30 0:00 /sbin/init
+root 17 0.0 0.0 10752 752 ? Ss 05:30 0:00 /usr/lib/systemd/systemd-readahead collect
+root 20 3.2 0.0 32740 2952 ? Ss 05:30 0:00 /usr/lib/systemd/systemd-journald
+root 34 0.0 0.0 22084 1452 ? Ss 05:30 0:00 /usr/lib/systemd/systemd-logind
+root 35 0.0 0.0 7724 612 ? Ss 05:30 0:00 /usr/bin/sleep 10000
+dbus 36 0.0 0.0 24288 1608 ? Ss 05:30 0:00 /bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation
+root 45 0.0 0.0 47452 1676 ? Rs 05:30 0:00 ps aux
+
+#cat /tmp/xxx
+{"ociVersion":"1.0.0","id":"c5b5eef81749ce00fb68a59ee623777bfecc8e07c617c0601cc56e4ae8b1e69f","status":"","pid":127183,"bundle":"/var/lib/pouch/containerd/state/io.containerd.runtime.v1.linux/default/c5b5eef81749ce00fb68a59ee623777bfecc8e07c617c0601cc56e4ae8b1e69f"}
+```
+
+## 底层实现
+
+在学习底层实现之前,我们将简要回顾一下`systemd`,`entrypoint`和`cmd`。 另外,prestart hook 由runC 执行。
+
+### systemd,entrypoint 和 cmd
+
+待补充。
+
+### initscript 和 runC
+
+`initscript`将被添加。
+
+`runc`是一个CLI工具,用于根据OCI规范生成和运行容器。
+
+
+
diff --git a/blog-en/PouchContainer Engineering Quality Practice.md b/blog-en/PouchContainer Engineering Quality Practice.md
new file mode 100644
index 0000000..e798b84
--- /dev/null
+++ b/blog-en/PouchContainer Engineering Quality Practice.md
@@ -0,0 +1,273 @@
+# 0.Preface
+
+
+
+As the function of [PouchContainer](https://github.com/alibaba/pouch) continues to be iterated and refined, the project has grown in size, attracting a number of external developers to participate in the development of the project. Because each contributor's coding habits are different, the code reviewer's responsibility is not only to focus on logical correctness and performance issues, but also on code style, since a uniform code specification is a prerequisite for maintaining project code maintainability. In addition to unifying the project code style, the coverage and stability of test cases is also the focus of the project. In a nutshell, in the absence of regression test cases, how do you ensure that each code update does not affect existing functions?
+
+This article shares PouchContainer's practices in code style specifications and golang unit test cases.
+
+# 1.Unified coding style specification
+
+PouchContainer is a project built by the golang language, which uses shell scripts to perform automated operations such as compiling and packaging. In addition to golang and shell scripts, PouchContainer also contains a large number of Markdown-style documents, which is the entry point for users to understand and understand PouchContainer. Its standard layout and correct spelling are also the focus of the project. The following sections will describe the tools and usage scenarios that PouchContainer uses in coding style specifications.
+
+## 1.1 Golinter - Unicode format
+
+Golang's grammar design is simple, and the community has a complete [CodeReview](https://github.com/golang/go/wiki/CodeReviewComments) guide from the beginning, so most of the golang projects have the same code style, and rarely fall into the unnecessary __religious__ dispute. On the basis of the community, PouchContainer also defines some specific rules to stipulate the developer. In order to ensure the readability of the code, the specific content can be read [here](https://github.com/alibaba/pouch/blob/master/docs/contributions/code_styles.md#additional-style-rules).
+
+However, it is difficult to ensure that the project code style is consistent with the written protocol alone. Therefore, like other languages, golang provides the official tool chain, such as [golint](https://github.com/golang/lint), [gofmt](https://golang.org/cmd/gofmt), [goimports](https://github.com/golang/tools/blob/master/cmd/goimports/doc.go), and [go vet](https://golang.org/cmd/vet), which can be used to check and unify code styles before compilation, and to automate subsequent processes such as code review. may. Currently, PouchContainer runs the above code checking tool in CircleCI __every__ Pull Request submitted by the developer. If the inspection tool displays an exception, the code reviewer has the right to __refuse__ the review and may even reject the merge code.
+
+In addition to the official tools provided, we can also select third-party code inspection tools in the open source community, such as [errcheck](https://github.com/kisielk/errcheck) to check if the developer has processed the error returned by the function. However, these tools do not have a uniform output format, which makes it difficult to integrate the output of different tools. Fortunately, some people in the open source community have implemented this unified interface that is [gometalinter](https://github.com/alecthomas/gometalinter), which can integrate various code checking tools. The recommended combination is:
+
+* [golint](https://github.com/golang/lint) - Google's (mostly stylistic) linter.
+* [gofmt -s](https://golang.org/cmd/gofmt/) - Checks if the code is properly formatted and could not be further simplified.
+* [goimports](https://godoc.org/golang.org/x/tools/cmd/goimports) - Checks missing or unreferenced package imports.
+* [go vet](https://golang.org/cmd/vet/) - Reports potential errors that otherwise compile.
+* [varcheck](https://github.com/opennota/check) - Find unused global variables and constants.
+* [structcheck](https://github.com/opennota/check) - Find unused struct fields
+* [errcheck](https://github.com/kisielk/errcheck) - Check that error return values are used.
+* [misspell](https://github.com/client9/misspell) - Finds commonly misspelled English words.
+
+Each project can customize the gometalinter package according to its own needs.
+
+## 1.2 Shellcheck - Reduce potential problems with shell scripts
+
+Although shell scripts are powerful, they still require syntax checking to avoid potential and unpredictable errors. For example, the definition of unused variables, although it does not affect the use of the script, its existence will become a burden on the project maintainer.
+
+```powershell
+#!/usr/bin/env bash
+
+pouch_version=0.5.x
+
+dosomething() {
+ echo "do something"
+}
+
+dosomething
+```
+
+PouchContainer will use [shellcheck](https://github.com/koalaman/shellcheck) to check the shell script in the current project. Taking the above code as an example, shellcheck detection will get a warning of unused variables. This tool can detect potential problems with shell scripts during the code review phase, reducing the chance of runtime errors.
+
+```plain
+In test.sh line 3:
+pouch_version=0.5.x
+^-- SC2034: pouch_version appears unused. Verify it or export it.
+```
+
+PouchContainer's current continuous integration task scans the ` .sh` scripts in the project and checks them one by one using shellcheck, as shown [here](https://github.com/alibaba/pouch/blob/master/.circleci/config.yml#L21-L24).
+
+> NOTE: When the shellcheck check is too strict, the project can be bypassed by a comment, or a check can be closed in the project. Specific inspection rules can be found [here](https://github.com/koalaman/shellcheck/wiki).
+
+## 1.3 Markdownlint - uniform document formatting
+
+PouchContainer is an open source project whose documentation is as important as the code, because documentation is the best way for users to understand PouchContainer. The document is written in the form of markdown, and its formatting and spelling errors are the focus of the project.
+
+Like the code, there is a text convention or a missed judgment, so PouchContainer uses [markdownlint](https://github.com/markdownlint/markdownlint) and [misspell](https://github.com/client9/misspell) to check the document format and spelling errors. These checks have the same status as `golint` and will run in CircleCI every time Pull Request occurs. Code reviewers have the right to __ refuse__ to review or merge the code Once an abnormality occurs.
+
+PouchContainer's current continuous integration task checks the markdown document formatting in the project and also checks the spelling in all files. The configuration can be found [here](https://github.com/alibaba/pouch/blob/master/.circleci/config.yml#L13-L20).
+
+> NOTE: When the markdownlint requirement is too strict, the corresponding check can be closed in the project. Specific inspection items can be found [here](https://github.com/markdownlint/markdownlint/blob/master/docs/RULES.md).
+
+## 1.4 Summary
+
+All of the above are style discipline issues, and PouchContainer automates code specification detection and integrates into each code review to help reviewers identify potential problems.
+
+# 2. How to write a unit test for golang
+
+Unit tests can be used to ensure the correctness of a single module. In the pyramid of test areas, the wider and more comprehensive the unit test coverage, the more it can reduce the debugging costs of integration testing and end-to-end testing. The complex System have the longer the link processed by the task, the higher the cost of the location problem, especially the problems caused by small modules. The following sections share a summary of PouchContainer's preparation of golang unit test cases.
+
+## 2.1 Table-Driven Test - DRY
+
+A simple understanding of unit testing is to give a given input to a function to determine if the expected output can be obtained. When the function being tested has a variety of input scenarios, we can organize our test cases in the form of Table-Driven, as shown in the next code. Table-Driven uses arrays to organize test cases and validate the correctness of the function by loop execution.
+
+```go
+// from https://golang.org/doc/code.html#Testing
+package stringutil
+
+import "testing"
+
+func TestReverse(t *testing.T) {
+ cases := []struct {
+ in, want string
+ }{
+ {"Hello, world", "dlrow ,olleH"},
+ {"Hello, 世界", "界世 ,olleH"},
+ {"", ""},
+ }
+ for _, c := range cases {
+ got := Reverse(c.in)
+ if got != c.want {
+ t.Errorf("Reverse(%q) == %q, want %q", c.in, got, c.want)
+ }
+ }
+}
+```
+
+To facilitate debugging and maintaining of test cases, we can add some auxiliary information to describe the current test. Such as the [reference](https://github.com/alibaba/pouch/blob/master/pkg/reference/parse_test.go#L54) to test the [punycode](https://en.wikipedia.org/wiki/Punycode) input, if you don't include the word punycode, they may not know the difference between `xn--bcher-kva.tld/redis:3` and `docker.io/library/redis: 3` for code reviewers or project maintainers.
+
+```go
+{
+ name: "Normal",
+ input: "docker.io/library/nginx:alpine",
+ expected: taggedReference{
+ Named: namedReference{"docker.io/library/nginx"},
+ tag: "alpine",
+ },
+ err: nil,
+}, {
+ name: "Punycode",
+ input: "xn--bcher-kva.tld/redis:3",
+ expected: taggedReference{
+ Named: namedReference{"xn--bcher-kva.tld/redis"},
+ tag: "3",
+ },
+ err: nil,
+}
+```
+
+However, some functions have complex behavior, and one input cannot be used as a complete test case. For example, [TestTeeReader](https://github.com/golang/go/blob/release-branch.go1.9/src/io/io_test.go#L284) and TeeReader read the hello, world
from the buffer, and the data has been read. If you read it again, the expected behavior is an end-of-file error. Such a test case needs to be done in a single case, without the need to hard-bake the form of Table-Driven.
+
+In simple terms, if you test a function that needs to copy most of the code, theoretically the test code can be extracted and used to organize test cases using Table-Driven. Don`t Repeat Yourself
+
+> NOTE: The Table-Driven organization is recommended by the golang community. Please check [here](https://github.com/golang/go/wiki/TableDrivenTests) for details.
+
+## 2.2 Mock - Simulating external dependence
+
+There are often problems with dependencies during the testing process. For example, the PouchContainer client requires an HTTP server, but this is too heavy for the unit, and this is a category of integration testing. So how to complete this part of the unit test?
+
+In the world of golang, the implementation of the interface belongs to [Duck Type](https://en.wikipedia.org/wiki/Duck_typing). An interface can have a variety of implementations, as long as the implementation conforms to the interface definition. If the external dependencies are constrained by the interface, then the dependency behavior is simulated in the unit test. The following content will share two common test scenarios.
+
+### 2.2.1 RoundTripper
+
+Take the PouchContainer client test as an example. The PouchContainer client uses [http.Client](https://golang.org/pkg/net/http/#Client), http.Client uses the [RoundTripper](https://golang.org/pkg/net/http/#RoundTripper) interface to execute an HTTP request, which allows developers to customize the logic of sending HTTP requests. It is also an important reason why golang can perfectly support the HTTP 2 protocol on an original basis.
+
+ ```plain
+http.Client -> http.RoundTripper [http.DefaultTransport]
+ ```
+
+For the PouchContainer client, the test focus is mainly on whether the incoming destination address is correct, whether the incoming query is reasonable, and whether the result can be returned normally and so on. So before testing, developers need to prepare the corresponding RoundTripper implementation, which is not responsible for the actual business logic, it is only used to determine whether the input meets expectations or not.
+
+As shown in the followings, PouchContainer `newMockClient` accepts customized request processing logic. In the test case of removing the image, the developer determines whether the destination address and the HTTP Method are DELETE in the customized logic, so that the functional test can be completed without starting the HTTP Server.
+
+```go
+// https://github.com/alibaba/pouch/blob/master/client/client_mock_test.go#L12-L22
+type transportFunc func(*http.Request) (*http.Response, error)
+
+func (transFunc transportFunc) RoundTrip(req *http.Request) (*http.Response, error) {
+ return transFunc(req)
+}
+
+func newMockClient(handler func(*http.Request) (*http.Response, error)) *http.Client {
+ return &http.Client{
+ Transport: transportFunc(handler),
+ }
+}
+
+// https://github.com/alibaba/pouch/blob/master/client/image_remove_test.go
+func TestImageRemove(t *testing.T) {
+ expectedURL := "/images/image_id"
+
+ httpClient := newMockClient(func(req *http.Request) (*http.Response, error) {
+ if !strings.HasPrefix(req.URL.Path, expectedURL) {
+ return nil, fmt.Errorf("expected URL '%s', got '%s'", expectedURL, req.URL)
+ }
+ if req.Method != "DELETE" {
+ return nil, fmt.Errorf("expected DELETE method, got %s", req.Method)
+ }
+
+ return &http.Response{
+ StatusCode: http.StatusNoContent,
+ Body: ioutil.NopCloser(bytes.NewReader([]byte(""))),
+ }, nil
+ })
+
+ client := &APIClient{
+ HTTPCli: httpClient,
+ }
+
+ err := client.ImageRemove(context.Background(), "image_id", false)
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+```
+
+
+
+### 2.2.2 MockImageManager
+
+For dependencies between internal packages, such as the PouchContainer Image API Bridge depends on the PouchContainer Daemon ImageManager, and the dependency behavior is defined by interface. If we want to test the logic of Image Bridge, we don't have to start containerd, we just need to implement the corresponding Daemon ImageManager like RoundTripper.
+
+```go
+// https://github.com/alibaba/pouch/blob/master/apis/server/image_bridge_test.go
+type mockImgePull struct {
+ mgr.ImageMgr
+ handler func(ctx context.Context, imageRef string, authConfig *types.AuthConfig, out io.Writer) error
+}
+
+func (m *mockImgePull) PullImage(ctx context.Context, imageRef string, authConfig *types.AuthConfig, out io.Writer) error {
+ return m.handler(ctx, imageRef, authConfig, out)
+}
+
+func Test_pullImage_without_tag(t *testing.T) {
+ var s Server
+
+ s.ImageMgr = &mockImgePull{
+ ImageMgr: &mgr.ImageManager{},
+ handler: func(ctx context.Context, imageRef string, authConfig *types.AuthConfig, out io.Writer) error {
+ assert.Equal(t, "reg.abc.com/base/os:7.2", imageRef)
+ return nil
+ },
+ }
+ req := &http.Request{
+ Form: map[string][]string{"fromImage": {"reg.abc.com/base/os:7.2"}},
+ Header: map[string][]string{},
+ }
+ s.pullImage(context.Background(), nil, req)
+}
+```
+
+
+
+### 2.2.3 Summary
+
+ImageManager and RoundTripper are modeled in the same way except for the number of functions defined by the interface. In general, developers can manually define a structure that uses methods as fields, as shown in the followings.
+
+ ```go
+type Do interface {
+ Add(x int, y int) int
+ Sub(x int, y int) int
+}
+
+type mockDo struct {
+ addFunc func(x int, y int) int
+ subFunc func(x int, y int) int
+}
+
+// Add implements Do.Add function.
+type (m *mockDo) Add(x int, y int) int {
+ return m.addFunc(x, y)
+}
+
+// Sub implements Do.Sub function.
+type (m *mockDo) Sub(x int, y int) int {
+ return m.subFunc(x, y)
+}
+ ```
+
+When the interface is large and complex, the manual method will impose a test burden on the developer, so the community provides automatically generated tools, such as [mockery](https://github.com/vektra/mockery), to ease the burden on the developer.
+
+## 2.3 Others
+
+Sometimes it relies on third-party services, such as the PouchContainer client, which is a typical case. The above describes Duck Type to complete the test of this case. In addition, we can also complete the request processing by registering the http.Handler and starting mockHTTPServer. This way of testing is relatively heavy, which is not recommended to use until the Duck Type can not test, or put it into the integration test.
+
+> NOTE: Someone in the golang community has accomplished [monkeypatch](https://github.com/bouk/monkey) by modifying the binary code. This tool is not recommended to use, it is still more advisable for developers to design and write testable code.
+
+## 2.4 Summary
+
+PouchContainer integrates unit test cases into the code review phase, and reviewers can view the running of test cases at any time.
+
+
+
+# 3. Summary
+
+In the code review phase, code style checking, unit testing, and integration testing should be run through continuous integration to help reviewers make accurate decisions. Currently, PouchContainer performs operations such as code style checks and tests primarily through TravisCI/CircleCI and [pouchrobot](https://github.com/pouchcontainer/pouchrobot).
\ No newline at end of file
diff --git a/blog-en/pouch_with_rich_container_modify.md b/blog-en/pouch_with_rich_container_modify.md
new file mode 100644
index 0000000..edf7c95
--- /dev/null
+++ b/blog-en/pouch_with_rich_container_modify.md
@@ -0,0 +1,122 @@
+# Rich Container
+
+Rich container is a very useful container mode when containerizing applications. This mode helps technical staff to complete packaging fat applications almost with no effort. It provides efficient ways to equip more basic software or system services except for target application in a single container. Then applications in containers could be running as smoothly as usual in VM or physical machine. This is a more generalized application-centric mode. This mode brings no invasiveness at all to both developers and operators. Especially for operators, they could have abilities to maintain applications in container with all essential tools or service processes they may need as usual.
+
+Rich container mode is not the default mode PouchContainer provides. It is an additional mode PouchContainer brings to extend users' container experience. Users can still manage ordinary containers by switching rich container flag off.
+
+In a word, rich container can help enterprise to achieve the following two goals:
+
+* be compatible with legacy operating system;
+* still take advantanges of image concept to speed up application delivery.
+
+## Scenario
+
+Container technology and orchestration platforms have turned quite popular right now. They both offer much better environment for applications. Despite this, we have to say containerization is the first step for enterprises to embrace container-related technologies, such as container, orchestration, service mesh and so on. It is quite a real problem to move traditional application into containers. Although some simple applications are always showing friendly to container, more traditional and complicated enterprise applications may not so lucky. These traditional applications are usually coupled with underlying infrastructure, such as architecture of machine, old kernels, even certain software out of maintenance as well. Definitely, strong coupling is not everyone's dish. It is the initiator on the road of digital transformation in enterprises. So, all the industry is seeking one possible way to work it out. The way docker provides is one, but not the best. In the past 7 years, Alibaba has also experienced the same issue. Fortunately, rich container mode is a much better way to handle this.
+
+Developers have their own programming style. Their work is to create useful applications, not to design absolute decoupled ones, so they usually take advantages of tools or system services to make it. When containerizing these applications, it is quite weak if only setting one application one process in container. Rich container mode finds out ways to make users configure the inner startup sequence of processes in container including application and system services around.
+
+Operators have a sacred duty to guard normal running of the applications. For the sake of business running in applications, technology must show enough respect for operator's tradition. Environment change is not a good message when debugging and solving issue online. Rich container mode can ensure that environment in rich container in totally the same as that in traditional VM or physical machine. If operator needs some system tools, they are located there still. If some pre and post hooks should take effect, just set them when starting rich containers. If some issues happen inside, system services started by rich container can fix them just like self-healing.
+
+## Architecture
+
+Rich container mode is compatible with the legacy operation ways for operation team. The following architecture graph shows how to achieve this:
+
+![pouch_with_rich_container](../static_files/pouch_with_rich_container.png)
+
+To be more detailed, rich container promises to be compatible with oci-compatible image. When running a rich container, pouchd would take image filesystem as the rootfs of rich container itself. In the runtime of inner container, besides inner applications and system servcies, there are also some hooks like prestart hook and poststop hook. The previous one focuses on how to prepare or intialize the environment before systemd and related process run. And the latter one is almost on cleanup work when container stops.
+
+## Get started
+
+Users can start rich container mode in PouchContainer quite easily. Provided that we need to running an ordinary image in rich container mode via PouchContainer, there are only two flags we may add: `--rich`,`--rich-mode`and `--initscript`. Here are more description about both flags:
+
+* `--rich`: identifies whether to switch on rich container mode or not. This flag has a type of `boolean`, and the default value is `false`.
+* `--rich-mode`: select which manner to init container, currently systemd, /sbin/init and dumb-init are supported. By default, it is dumb-init.
+* `--initscript`: identifies initial script executed in container. The script will be executed before entrypoint or command. Sometimes, it is called prestart hook. Lots of work can be done in this prestart hook, such as environment checking, environment preparation, network routes preparation, all kinds of agent settings, security setting and so on. This initscript may fail and user gets an related error message, if pouchd cannot find this initscript in container's filesystem which is provided by the rootfs constructed from image and potential mount volumes actually outside the container. If initscript works fine, the control of container process would be taken over by process pid 1, mainly `/sbin/init` or `dumbinit`.
+
+In fact, PouchContainer team plans to add another flag `--initcmd` to make users input prestart hook. Actually it is a simplified one of `--initscript`. Meanwhile it brings more convenience than `--initscript`. `--initcmd` can set any command as user's wish, and things do not need to be located in image in advance. We can say command is decoupled with image. But for `--initscript`, script file must be located in image first. It is some kind of coupling.
+
+If user specifies `--rich` flag and no `--initscript` flag is provided, rich container mode will still be enabled, but no initscript will be executed. If `--rich` flag misses in command line, while `--initscript` is there, PouchContainer CLI or pouchd will return an error to show that `--initscipt` can only be used along with `--rich` flag.
+
+If a container is running with `--rich` flag, then every start or restart of this container will trigger the corresponding initscipt if there is any.
+
+### Using dumb-init
+
+Here is a simple example for rich container mode using dumb-init to init container:
+
+1. Install dumb-init as following:
+
+```shell
+# wget -O /usr/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v1.2.1/dumb-init_1.2.1_amd64
+# chmod +x /usr/bin/dumb-init
+```
+
+2. Run a container with rich mode:
+
+```shell
+#pouch run -d --rich --rich-mode dumb-init registry.hub.docker.com/library/busybox:latest sleep 10000
+f76ac1e49e9407caf5ad33c8988b44ff3690c12aa98f7faf690545b16f2a5cbd
+
+#pouch exec f76ac1e49e9407caf5ad33c8988b44ff3690c12aa98f7faf690545b16f2a5cbd ps -ef
+PID USER TIME COMMAND
+1 root 0:00 /usr/bin/dumb-init -- sleep 10000
+7 root 0:00 sleep 10000
+8 root 0:00 ps -ef
+```
+
+### Using systemd or sbin-init
+
+In order to use systemd or /sbin/init to init container, please make sure install them on image.
+As shown below, centos image has both of them.
+Also `--privileged` is required in this situation. An example of systemd and sbin-init is as following:
+
+```
+#cat /tmp/1.sh
+#! /bin/sh
+echo $(cat) >/tmp/xxx
+
+#pouch run -d -v /tmp:/tmp --privileged --rich --rich-mode systemd --initscript /tmp/1.sh registry.hub.docker.com/library/centos:latest /usr/bin/sleep 10000
+3054125e44443fd5ee9190ee49bbca0a842724f5305cb05df49f84fd7c901d63
+
+#pouch exec 3054125e44443fd5ee9190ee49bbca0a842724f5305cb05df49f84fd7c901d63 ps aux
+USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
+root 1 7.4 0.0 42968 3264 ? Ss 05:29 0:00 /usr/lib/systemd/systemd
+root 17 0.0 0.0 10752 756 ? Ss 05:29 0:00 /usr/lib/systemd/systemd-readahead collect
+root 18 3.2 0.0 32740 2908 ? Ss 05:29 0:00 /usr/lib/systemd/systemd-journald
+root 34 0.0 0.0 22084 1456 ? Ss 05:29 0:00 /usr/lib/systemd/systemd-logind
+root 36 0.0 0.0 7724 608 ? Ss 05:29 0:00 /usr/bin/sleep 10000
+dbus 37 0.0 0.0 24288 1604 ? Ss 05:29 0:00 /bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation
+root 45 0.0 0.0 47452 1676 ? Rs 05:29 0:00 ps aux
+
+#cat /tmp/xxx
+{"ociVersion":"1.0.0","id":"3054125e44443fd5ee9190ee49bbca0a842724f5305cb05df49f84fd7c901d63","status":"","pid":125745,"bundle":"/var/lib/pouch/containerd/state/io.containerd.runtime.v1.linux/default/3054125e44443fd5ee9190ee49bbca0a842724f5305cb05df49f84fd7c901d63"}
+
+#pouch run -d -v /tmp:/tmp --privileged --rich --rich-mode sbin-init --initscript /tmp/1.sh registry.hub.docker.com/library/centos:latest /usr/bin/sleep 10000
+c5b5eef81749ce00fb68a59ee623777bfecc8e07c617c0601cc56e4ae8b1e69f
+
+#pouch exec c5b5eef81749ce00fb68a59ee623777bfecc8e07c617c0601cc56e4ae8b1e69f ps aux
+USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
+root 1 7.4 0.0 42968 3260 ? Ss 05:30 0:00 /sbin/init
+root 17 0.0 0.0 10752 752 ? Ss 05:30 0:00 /usr/lib/systemd/systemd-readahead collect
+root 20 3.2 0.0 32740 2952 ? Ss 05:30 0:00 /usr/lib/systemd/systemd-journald
+root 34 0.0 0.0 22084 1452 ? Ss 05:30 0:00 /usr/lib/systemd/systemd-logind
+root 35 0.0 0.0 7724 612 ? Ss 05:30 0:00 /usr/bin/sleep 10000
+dbus 36 0.0 0.0 24288 1608 ? Ss 05:30 0:00 /bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation
+root 45 0.0 0.0 47452 1676 ? Rs 05:30 0:00 ps aux
+
+#cat /tmp/xxx
+{"ociVersion":"1.0.0","id":"c5b5eef81749ce00fb68a59ee623777bfecc8e07c617c0601cc56e4ae8b1e69f","status":"","pid":127183,"bundle":"/var/lib/pouch/containerd/state/io.containerd.runtime.v1.linux/default/c5b5eef81749ce00fb68a59ee623777bfecc8e07c617c0601cc56e4ae8b1e69f"}
+```
+
+## Underlying Implementation
+
+Before learning underlying implementation we shall take a brief review of `systemd`, `entrypoint` and `cmd`. In addition, prestart hook is executed by runC.
+
+### systemd, entrypoint and cmd
+
+To be added
+
+### initscript and runC
+
+`initscript` is to be added.
+
+`runc` is a CLI tool for spawning and running containers according to the OCI specification.