{"action":"created","issue":{"url":"https://api.github.com/repos/zhouhaibing089/Blog/issues/8","repository_url":"https://api.github.com/repos/zhouhaibing089/Blog","labels_url":"https://api.github.com/repos/zhouhaibing089/Blog/issues/8/labels{/name}","comments_url":"https://api.github.com/repos/zhouhaibing089/Blog/issues/8/comments","events_url":"https://api.github.com/repos/zhouhaibing089/Blog/issues/8/events","html_url":"https://github.com/zhouhaibing089/Blog/issues/8","id":123791815,"number":8,"title":"Kubernetes笔记(1)","user":{"login":"zhouhaibing089","id":4516999,"avatar_url":"https://avatars.githubusercontent.com/u/4516999?v=3","gravatar_id":"","url":"https://api.github.com/users/zhouhaibing089","html_url":"https://github.com/zhouhaibing089","followers_url":"https://api.github.com/users/zhouhaibing089/followers","following_url":"https://api.github.com/users/zhouhaibing089/following{/other_user}","gists_url":"https://api.github.com/users/zhouhaibing089/gists{/gist_id}","starred_url":"https://api.github.com/users/zhouhaibing089/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/zhouhaibing089/subscriptions","organizations_url":"https://api.github.com/users/zhouhaibing089/orgs","repos_url":"https://api.github.com/users/zhouhaibing089/repos","events_url":"https://api.github.com/users/zhouhaibing089/events{/privacy}","received_events_url":"https://api.github.com/users/zhouhaibing089/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":11,"created_at":"2015-12-24T11:04:32Z","updated_at":"2016-08-16T07:09:49Z","closed_at":null,"body":"[Kubernetes](http://kubernetes.io/)是一个集群管理的分布式系统, 尤其, 它管理的对象是容器.\r\n\r\n从前, 开发者的应用如果要部署, 首先, 他需要找一台物理机, 装好整个应用栈, 最后把程序部署在上面.\r\n\r\n后来, 为了能更好地进行弹性伸缩, 一台物理机需要拆分使用, 于是虚拟化技术得到了广泛的应用, 它带来的好处是每个应用使用的资源都能够进行进行灵活调配, 从而使得物理机器的使用率得到提高.\r\n\r\n不过由于每台虚拟机都有独自的操作系统栈, 一台物理机上同时运行着多个内核, 看起来并不是那么美好. \r\n\r\n后来随着cgroups和namespace技术的成熟, 在内核上做资源隔离成为了可能,  于是容器技术成为了当下的时髦标杆. 所谓容器技术, 就是让每个应用运行在各自的namespace中, 它们共用同一个kernel, 同享硬件资源, 但是应用之间又能够做到足够安全的隔离.\r\n\r\n### Kubernete的编译\r\n\r\n获取Kubernetes的代码并进行编译十分简单:\r\n\r\n```\r\ngit clone https://github.com/kubernetes/kubernetes.git\r\ncd kubernetes\r\nmake quick-release\r\n```\r\n\r\n不过在这之前, 我们首先需要确保在系统中有一个可以运行的docker环境, 因为Kubernetes的编译过程运行在容器中. 一般来说, 我们要编译, 都需要在本机安装好一系列的工具, 要确保依赖的一些库都已经安装, 但在容器技术的背景下, 这个编译环境可以作为一个容器运行, 完事之后, 直接删除就可, 丝毫不会污染本机环境, 嗯, 看起来是不是很酷, ^_^.\r\n\r\n现在我们一起来看看`make quick-release`都做了些什么事情.\r\n\r\n从`Makefile`我们可知, 该命令其实就是执行了`build/release.sh`文件, 在该文件中, 我们可以大致看出, 整个过程分为以下几个步骤:\r\n\r\n1.  环境检查\r\n2.  构建Image\r\n3.  以该Image启动容器执行编译\r\n4.  将编译产生的文件拷贝到本地\r\n5.  打包\r\n\r\n#### 环境检查\r\n\r\n这一步主要是确认docker环境, 尤其的, 对于OSX系统, 会检查是否安装了`docker-machine`或者`boot2docker`, 如果OK的话, 会进一步确认当前是否存在名为`kube-dev`的虚拟环境, 如果没有, 则创建一个. 在`build/common.sh`文件中, 可以看到, 创建`kube-dev`环境执行的命令为:\r\n\r\n````sh\r\n# build/common.sh\r\ndocker-machine create -d virtualbox kube-dev > /dev/null || {\r\n  ...\r\n}\r\n```\r\n\r\n如果你觉得有必要对该环境做进一步的定制化, 可在此处修改, 比如你需要配置`--insecure-registry`(见于你搭建了自己的registry), 又或者你需要在该环境中预设一些环境变量(比如设置`http_proxy`与`https_proxy`), 可以稍作修改:\r\n\r\n````sh\r\n# build/common.sh\r\ndocker-machine create -d virtualbox \\\r\n  --engine-insecure-registry ${registry} \\\r\n  --engine-env ${key}=${value} kube-dev > /dev/null || {\r\n  ...\r\n}\r\n```\r\n\r\n#### 构建Image\r\n\r\n此处需要构建两个Image, 第一个是`kube-build:cross`, 它的Dockerfile位于`build/build-image/cross/Dockerfile`, 大致看下来, 该Image基于`golang:1.4`, 同时做了些工作来支持多平台编译, 具体方法为先设置对应的平台信息环境变量, 再执行`$GOROOT/src/make.bash --no-clean`.\r\n\r\n第二个Image基于上面所构建的Image, 它的Dockerfile位于`build/build-image/Dockerfile`, 在该文件中, 最主要的是指定了以下几件事情:\r\n\r\n1.  设置`GOARM=5`, `GOARCH=amd64`, `GOOS=linux`环境变量.\r\n2.  安装`rsync`, `etcd`\r\n3.  添加文件`kube-version-defs`和`kube-source.tar.gz`\r\n\r\n**kube-version-defs**文件中的内容产生于`hack/lib/version.sh`, 大概为:\r\n\r\n```sh\r\n# _output/images/kube-build:build-${KUBE_ROOT_HASH}\r\nKUBE_GIT_COMMIT='21c01c05e3af2c33ad2c9e6647704113d10967f2'\r\nKUBE_GIT_TREE_STATE='dirty'\r\nKUBE_GIT_VERSION=''\r\nKUBE_GIT_MAJOR=''\r\nKUBE_GIT_MINOR=''\r\n```\r\n\r\n**kube-source.tar.gz**打包的文件夹包括:\r\n\r\n```sh\r\n# build/common.sh\r\nlocal targets=(\r\n  api\r\n  build\r\n  cluster\r\n  cmd\r\n  docs\r\n  examples\r\n  Godeps/_workspace/src\r\n  Godeps/Godeps.json\r\n  hack\r\n  LICENSE\r\n  pkg\r\n  plugin\r\n  DESIGN.md\r\n  README.md\r\n  test\r\n  third_party\r\n  contrib/completions/bash/kubectl\r\n  .generated_docs\r\n)\r\n```\r\n\r\n如果还有指定`KUBERNETES_CONTRIB`, 那么还会将`kube::contrib::${contrib}::source_targets`函数的返回结果中指定的文件夹添加进来, 比如`contrib/mesos/target.sh`中的`kube::contrib::mesos::source_targets`.\r\n\r\n#### 执行编译\r\n\r\n这个过程调用的函数是`kube::build::run_build_command hack/build-cross.sh`, 它位于`build/common.sh`, 在该函数中, 它做了这么几件事情:\r\n\r\n1.  执行下面的命令创建第一个容器:\r\n\r\n    ```sh\r\n    # build/common.sh\r\n    docker run \\\r\n      --volume /go/src/k8s.io/kubernetes/_output/dockerized/go \\\r\n      --volume /go/src/k8s.io/kubernetes/Godeps/_workspace/pkg \\\r\n      --name kube-build-data-${KUBE_ROOT_HASH} \\\r\n      kube-build:build-${KUBE_ROOT_HASH} \\\r\n      true\r\n    ```\r\n    该容器只是挂载了两个文件夹并简单的运行了一条`true`命令.\r\n2.  创建第二个容器, 并执行构建\r\n\r\n    ```sh\r\n    # build/common.sh\r\n    docker run \\\r\n      --name kube-build-${KUBE_ROOT_HASH} \\\r\n      --volume _output/dockerized/bin:/go/src/k8s.io/kubernetes/_output/dockerized/bin \\\r\n      --volumes-from kube-build-data-${KUBE_ROOT_HASH} \\\r\n      -e KUBERNETES_CONTRIB=${KUBERNETES_CONTRIB} \\\r\n      --interactive --tty \\\r\n      kube-build:build-${KUBE_ROOT_HASH} \\\r\n      hack/build-cross.sh\r\n    ```\r\n    它做的事情是挂载`_output/dockerized/bin`目录, 打开tty并执行`hack/build-cross.h`.\r\n\r\n关于这部分编译过程, 我还没有深入研究, 但就目前的了解来说, 它为各个平台编译了以下这些可执行文件:\r\n\r\n```sh\r\n# server端, 包括linux/amd64和linux/arm\r\ncmd/kube-proxy\r\ncmd/kube-apiserver\r\ncmd/kube-controller-manager\r\ncmd/kubelet\r\ncmd/kubemark\r\ncmd/hyperkube\r\ncmd/linkcheck\r\nplugin/cmd/kube-scheduler\r\n# client端, 包括linux/amd64, linux/386, linux/arm, darwin/amd64, darwin/386, windows/amd64\r\ncmd/kubectl\r\n# 下面的这些是为测试而编译的\r\ncmd/integration\r\ncmd/gendocs\r\ncmd/genkubedocs\r\ncmd/genman\r\ncmd/mungedocs\r\ncmd/genbashcomp\r\ncmd/genconversion\r\ncmd/gendeepcopy\r\ncmd/genswaggertypedocs\r\nexamples/k8petstore/web-server/src\r\ngithub.com/onsi/ginkgo/ginkgo\r\ntest/e2e/e2e.test\r\n```\r\n\r\n#### 拷贝到本地\r\n\r\n最后这些文件会通过rsync拷贝到`_output/local/bin/${platform}`中, 接下来, 如果本机是mac或windows的话, 还需要使用`docker cp`来将上面的文件拷贝到本地, 即`_output/dockerized/bin`目录中.\r\n\r\n具体执行过程为:\r\n\r\n```sh\r\n# 拷贝到容器的/tmp/bin目录\r\ncp -r _output/local/bin /tmp/bin\r\n# 创建另外一个测试文件\r\ntouch /tmp/finished\r\n# 删除\r\nrm /tmp/test_for_remote\r\n# 等待600ms\r\n/bin/sleep 600\r\n# 使用docker cp命令\r\ndocker ... cp kube-build-${KUBE_ROOT_HASH}:/tmp/bin _output/dockerized\r\n```\r\n\r\n#### 打包\r\n\r\n打包过程比较简单, 从`kube::release::package_tarballs`函数中可以看到我们一共需要执行以下几个过程:\r\n\r\n```sh\r\nkube::release::package_client_tarballs\r\nkube::release::package_server_tarballs\r\nkube::release::package_salt_tarball\r\nkube::release::package_kube_manifests_tarball\r\nkube::release::package_full_tarball\r\nkube::release::package_test_tarball\r\n```\r\n\r\n其中每个函数都会先将要打包的文件准备到`_output/release-stage`中, 再将打包的文件复制到`_output/release-tars`.\r\n\r\n**kubernets-client-${os}-${arch}.tar.gz**\r\n\r\n包含有`kubectl`命令行工具.\r\n\r\n**kubernetes-manifests.tar.gz**\r\n\r\n包含有`fluentd-es.yaml`, `fluentd-gcp.yaml`和`kube-registry-proxy.yaml`, 这几个文件是代码中写死的.\r\n\r\n**kubernetes-salt.tar.gz**\r\n\r\n该压缩包就是来自于`cluster/saltbase`.\r\n\r\n**kubernets-server-${os}-${arch}.tar.gz**\r\n\r\n该压缩包包含两部分内容, 一个是上面提到需要的二进制文件, 另外还包括两个构建好的Image的tar包, 他们是`gcr.io/google_containers/pause:2.0`和`gcr.io/google_containers/kube-registry-proxy:0.3`.\r\n\r\n**kubenetets.tar.gz**\r\n\r\n总的打包文件, 包括上面提到的这些文件, 还包括`cluster`, `contrib`, `docs`, `examples`, `third_party`, `Vagrantfile`, 这是作为一个总的发行包.\r\n\r\n#### 总结\r\n\r\n到现在我们已经大概清楚了整个编译过程, 接下来我们要做的是真正启动一个Kubernetes集群, 在接下来的例子中, 我使用Vagrant来做VM的provisioning过程, 那么那里又有些什么神奇的故事呢, 敬请期待下一记.\r\n\r\n"},"comment":{"url":"https://api.github.com/repos/zhouhaibing089/Blog/issues/comments/240020981","html_url":"https://github.com/zhouhaibing089/Blog/issues/8#issuecomment-240020981","issue_url":"https://api.github.com/repos/zhouhaibing089/Blog/issues/8","id":240020981,"user":{"login":"jianzhangbjz","id":15416633,"avatar_url":"https://avatars.githubusercontent.com/u/15416633?v=3","gravatar_id":"","url":"https://api.github.com/users/jianzhangbjz","html_url":"https://github.com/jianzhangbjz","followers_url":"https://api.github.com/users/jianzhangbjz/followers","following_url":"https://api.github.com/users/jianzhangbjz/following{/other_user}","gists_url":"https://api.github.com/users/jianzhangbjz/gists{/gist_id}","starred_url":"https://api.github.com/users/jianzhangbjz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jianzhangbjz/subscriptions","organizations_url":"https://api.github.com/users/jianzhangbjz/orgs","repos_url":"https://api.github.com/users/jianzhangbjz/repos","events_url":"https://api.github.com/users/jianzhangbjz/events{/privacy}","received_events_url":"https://api.github.com/users/jianzhangbjz/received_events","type":"User","site_admin":false},"created_at":"2016-08-16T07:09:49Z","updated_at":"2016-08-16T07:09:49Z","body":"@zhouhaibing089 因为有些node上是没有那些硬件的"}}
{"actor":{"display_login":"jianzhangbjz"}}