{"id":403536,"date":"2024-06-29T17:11:06","date_gmt":"2024-06-29T17:11:06","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=403536"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=403536","title":{"rendered":"<span>\u042d\u0432\u043e\u043b\u044e\u0446\u0438\u044f Docker. \u0427\u0430\u0441\u0442\u044c 1<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<h2>\u0412\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0435<\/h2>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/getpro\/habr\/upload_files\/0b2\/e6e\/dc2\/0b2e6edc2fa786a32c07d0b03db15d66.jpg\" alt=\"The future of Linux Containers\" title=\"The future of Linux Containers\" width=\"1011\" height=\"505\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/0b2\/e6e\/dc2\/0b2e6edc2fa786a32c07d0b03db15d66.jpg\" data-blurred=\"true\"\/><figcaption>The future of Linux Containers<\/figcaption><\/figure>\n<p>20 \u043c\u0430\u0440\u0442\u0430 2013 \u0433\u043e\u0434\u0430 \u043d\u0430 \u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u0438 PyCon 2013, \u0421\u043e\u043b\u043e\u043c\u043e\u043d \u0425\u0430\u0439\u043a\u0441 (CEO \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438 dotCloud) \u0432\u044b\u0441\u0442\u0443\u043f\u0438\u043b \u0441 \u043f\u044f\u0442\u0438\u043c\u0438\u043d\u0443\u0442\u043d\u043e\u0439 \u043f\u0440\u0435\u0437\u0435\u043d\u0442\u0430\u0446\u0438\u0435\u0439 <a href=\"https:\/\/www.youtube.com\/watch?v=wW9CAH9nSLs\" rel=\"noopener noreferrer nofollow\">The future of Linux Containers<\/a>. \u0412 \u043d\u0435\u0439 \u0448\u0438\u0440\u043e\u043a\u043e\u0439 \u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u0432\u043f\u0435\u0440\u0432\u044b\u0435 \u0431\u044b\u043b\u0430 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u044f\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438 dotCloud \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c Docker, \u0430 \u0441\u043f\u0443\u0441\u0442\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0434\u043d\u0435\u0439 \u0435\u0435 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u0431\u044b\u043b \u0432\u044b\u043b\u043e\u0436\u0435\u043d \u0432 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0439 \u0434\u043e\u0441\u0442\u0443\u043f. \u0425\u043e\u0442\u044f \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438 <a href=\"https:\/\/ru.wikipedia.org\/wiki\/LXC\" rel=\"noopener noreferrer nofollow\">LXC<\/a> \u0438 <a href=\"https:\/\/ru.wikipedia.org\/wiki\/Aufs\" rel=\"noopener noreferrer nofollow\">Aufs<\/a>, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0431\u044b\u043b\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0430 \u043f\u0435\u0440\u0432\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f Docker \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043b\u0438 \u0438 \u0430\u043a\u0442\u0438\u0432\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438\u0441\u044c \u0443\u0436\u0435 \u043f\u043e\u0440\u044f\u0434\u043a\u0430 \u043f\u044f\u0442\u0438 \u043b\u0435\u0442, \u043d\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u0435 Docker \u043f\u043e\u0441\u043b\u0443\u0436\u0438\u043b\u043e \u043d\u0430\u0447\u0430\u043b\u043e\u043c \u0441\u0442\u0440\u0435\u043c\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0440\u043e\u0441\u0442\u0430 \u0438 \u044d\u0432\u043e\u043b\u044e\u0446\u0438\u0438 \u0441\u0438\u0441\u0442\u0435\u043c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u0438, \u0447\u0442\u043e \u043a\u0430\u0440\u0434\u0438\u043d\u0430\u043b\u044c\u043d\u043e \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0438\u043b\u043e \u043c\u043d\u043e\u0433\u0438\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u0434\u0435\u043f\u043b\u043e\u0439\u043c\u0435\u043d\u0442\u0430 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e\u0433\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f.<\/p>\n<p>\u042d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435\u0439 \u044f \u0441\u043e\u0431\u0438\u0440\u0430\u044e\u0441\u044c \u043d\u0430\u0447\u0430\u0442\u044c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0446\u0438\u043a\u043b \u043f\u043e\u0441\u0432\u044f\u0449\u0435\u043d\u043d\u044b\u0439 \u0438\u0437\u0443\u0447\u0435\u043d\u0438\u044e \u0440\u0430\u0437\u0432\u0438\u0442\u0438\u044f \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 Docker \u043d\u0430 \u043f\u0440\u043e\u0442\u044f\u0436\u0435\u043d\u0438\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043b\u0435\u0442. \u0412 \u043f\u0435\u0440\u0432\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u043b \u0441\u043e\u0431\u043e\u0439 \u043a\u043e\u0434 \u043d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f git \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u0434\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u044f\u043d\u0432\u0430\u0440\u0435\u043c 2013 \u0433\u043e\u0434\u0430. \u0422\u043e\u0433\u0434\u0430 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 Docker (\u0437\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u0442\u0435\u0441\u0442\u043e\u0432) \u0441\u043e\u0441\u0442\u043e\u044f\u043b \u0432\u0441\u0435\u0433\u043e \u0438\u0437 \u0448\u0435\u0441\u0442\u0438 \u0444\u0430\u0439\u043b\u043e\u0432 \u043e\u0431\u0449\u0438\u043c \u043e\u0431\u044a\u0435\u043c\u043e\u043c ~600 \u0441\u0442\u0440\u043e\u043a \u043a\u043e\u0434\u0430, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0445 \u043d\u0430 \u044f\u0437\u044b\u043a\u0435 Go. \u042d\u0442\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u043f\u043e\u0445\u043e\u0434\u0438\u043b\u043e \u043d\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443\/api, \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0441\u043e\u0441\u0442\u043e\u044f\u043b \u043b\u0438\u0448\u044c \u0432 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438, \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0438, \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0438 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0435 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432. \u041c\u044b \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u043f\u0440\u0438\u043d\u0446\u0438\u043f \u0440\u0430\u0431\u043e\u0442\u044b \u0438 \u0434\u0430\u0436\u0435 \u0441\u043c\u043e\u0436\u0435\u043c \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0441 \u0435\u0435 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440.\u00a0<\/p>\n<p>\u0412\u043e \u0432\u0442\u043e\u0440\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0435\u043c\u0441\u044f \u043d\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0435\u0441\u044f\u0446\u0435\u0432 \u0432\u043f\u0435\u0440\u0435\u0434 &#8212; \u0432 \u043c\u0430\u0440\u0442 2013, \u043a\u043e\u0433\u0434\u0430 \u0434\u043e\u043a\u0435\u0440 \u0431\u044b\u043b \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u043d\u0430 \u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u0438 PyCon. \u041d\u0430 \u0442\u043e\u0442 \u043c\u043e\u043c\u0435\u043d\u0442 \u043e\u043d \u0443\u0436\u0435 \u043e\u0431\u043b\u0430\u0434\u0430\u043b \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u0441\u0435\u043c\u0438 \u0437\u043d\u0430\u043a\u043e\u043c\u044b\u043c\u0438 \u043d\u0430\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c\u0438. \u0410 \u0432 \u0442\u0440\u0435\u0442\u044c\u0435\u0439 \u0447\u0430\u0441\u0442\u0438 \u044f \u043f\u043e\u0441\u0442\u0430\u0440\u0430\u044e\u0441\u044c \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043f\u0435\u0440\u0435\u0445\u043e\u0434 Docker \u0441 LXC \u043d\u0430 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u0443\u044e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443, \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u0435\u0434\u0448\u0438\u0439 \u0433\u043e\u0434\u043e\u043c \u043f\u043e\u0437\u0436\u0435.<\/p>\n<h2>\u0418\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434<\/h2>\n<p>\u0414\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u044f \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Windows 10 c Vagrant \u0438 Ubuntu 20.04. \u0421\u0440\u0430\u0437\u0443 \u0445\u043e\u0447\u0443 \u043f\u0440\u0435\u0434\u0443\u043f\u0440\u0435\u0434\u0438\u0442\u044c, \u0447\u0442\u043e WSL2 \u043d\u0435 \u043f\u043e\u0434\u043e\u0439\u0434\u0435\u0442, \u0442\u0430\u043a \u043a\u0430\u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u043e\u0435 \u044f\u0434\u0440\u043e \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 aufs, \u0442\u0440\u0435\u0431\u0443\u0435\u043c\u0443\u044e \u0432 \u0440\u0430\u043d\u043d\u0438\u0445 \u0432\u0435\u0440\u0441\u0438\u044f\u0445.<\/p>\n<p>\u0412 \u043f\u0435\u0440\u0432\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u043a\u0430\u0447\u0430\u0442\u044c \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 <a href=\"https:\/\/github.com\/docker\/engine.git\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/docker\/engine.git<\/a> \u0438\u043b\u0438 <a href=\"https:\/\/github.com\/moby\/moby.git\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/moby\/moby.git<\/a>.\u00a0\u0421\u043a\u043b\u043e\u043d\u0438\u0440\u0443\u0435\u043c \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0438 \u0432\u0435\u0440\u043d\u0435\u043c\u0441\u044f \u043a \u043d\u0430\u0447\u0430\u043b\u0443 \u0438\u0441\u0442\u043e\u0440\u0438\u0438 (\u0445\u0435\u0448 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u043a\u043e\u043c\u043c\u0438\u0442\u0430 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 <em>git log &#8212;reverse<\/em>).<\/p>\n<pre><code class=\"bash\">cd \/home\/vagrant &amp;&amp; git clone https:\/\/github.com\/docker\/engine.git &amp;&amp; cd .\/engine git checkout -f a27b4b8cb8e838d03a99b6d2b30f76bdaf2f9e5d &amp;&amp; wc -l $(ls -1 | grep -v test) HEAD is now at a27b4b8cb8 Initial commit   203 container.go   112 docker.go    52 filesystem.go    94 lxc_template.go    48 state.go   115 utils.go   624 total <\/code><\/pre>\n<p>\u041d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f (18 \u044f\u043d\u0432\u0430\u0440\u044f 2013 \u0433\u043e\u0434\u0430), \u043a\u043e\u0434 Docker \u0441\u043e\u0441\u0442\u043e\u044f\u043b \u0432\u0441\u0435\u0433\u043e \u0438\u0437 6 \u0444\u0430\u0439\u043b\u043e\u0432 \u043e\u0431\u0449\u0438\u043c \u043e\u0431\u044a\u0435\u043c\u043e\u043c \u0432 624 \u0441\u0442\u0440\u043e\u043a\u0438 \u0438 \u043a\u0430\u043a \u043c\u044b \u0443\u0432\u0438\u0434\u0438\u043c \u0434\u0430\u043b\u0435\u0435, \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u043b \u0441\u043e\u0431\u043e\u0439 \u043b\u0438\u0448\u044c \u043e\u0431\u0435\u0440\u0442\u043a\u0443 \u0438 \u0443\u0434\u043e\u0431\u043d\u043e\u0435 api \u0434\u043b\u044f \u0443\u0442\u0438\u043b\u0438\u0442 <strong>lxc<\/strong> \u0438 <strong>mount<\/strong>.<\/p>\n<p>\u0418\u0442\u0430\u043a, \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a \u0438\u0437\u0443\u0447\u0435\u043d\u0438\u044e \u0441\u0430\u043c\u043e\u0433\u043e \u043a\u043e\u0434\u0430, \u043e\u0442\u043f\u0440\u0430\u0432\u043d\u043e\u0439 \u0442\u043e\u0447\u043a\u043e\u0439 \u0431\u0443\u0434\u0435\u0442 \u0441\u043b\u0443\u0436\u0438\u0442\u044c \u0444\u0430\u0439\u043b <strong>docker.go<\/strong>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u044b \u0444\u0443\u043d\u043a\u0446\u0438\u0438 New \u0438 NewFromDirectory:<\/p>\n<pre><code class=\"go\">type Docker struct { root       string repository string containers *list.List }  func New() (*Docker, error) { return NewFromDirectory(\"\/var\/lib\/docker\") }  func NewFromDirectory(root string) (*Docker, error) { docker := &amp;Docker{ root:       root, repository: path.Join(root, \"containers\"), containers: list.New(), }  if err := os.Mkdir(docker.repository, 0700); err != nil &amp;&amp; !os.IsExist(err) { return nil, err }  if err := docker.restore(); err != nil { return nil, err } return docker, nil } <\/code><\/pre>\n<p>New \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0444\u0430\u0441\u0430\u0434\u043e\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 NewFromDirectory \u0441 \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u044b\u043c \u043f\u0443\u0442\u0435\u043c \/var\/lib\/docker. \u0424\u0443\u043d\u043a\u0446\u0438\u044f NewFromDirectory \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b Docker, \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \u0434\u043b\u044f \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432 (\u0435\u0441\u043b\u0438 \u043e\u043d\u0430 \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442) \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 Docker (\u043f\u0435\u0440\u0435\u0434 \u0447\u0435\u043c \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043c\u0435\u0442\u043e\u0434 restore):<\/p>\n<pre><code class=\"go\">func (docker *Docker) restore() error { dir, err := ioutil.ReadDir(docker.repository) if err != nil { return err } for _, v := range dir { container, err := loadContainer(path.Join(docker.repository, v.Name())) if err != nil { fmt.Errorf(\"Failed to load %v: %v\", v.Name(), err) continue } docker.containers.PushBack(container) } return nil }<\/code><\/pre>\n<p>\u0412 \u043c\u0435\u0442\u043e\u0434\u0435 restore \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432 \u0438\u0437 \u043f\u0430\u043f\u043a\u0438 containers \u0432\u044b\u0437\u043e\u0432\u043e\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u0438 loadContainer. \u041f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0434\u0430\u043d\u043d\u0430\u044f \u043f\u0430\u043f\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u043f\u0443\u0441\u0442\u0430, \u0442\u0430\u043a \u0447\u0442\u043e \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0435\u0442. \u041c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0434\u0430\u043d\u043d\u044b\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043f\u043e\u0437\u0436\u0435, \u043a\u043e\u0433\u0434\u0430 \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a \u0444\u0430\u0439\u043b\u0443 <strong>container.go<\/strong>.<\/p>\n<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u044e\u0449\u0438\u0435 \u043d\u0430\u0441 \u043c\u0435\u0442\u043e\u0434\u044b \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 docker.go \u044d\u0442\u043e Create \u0438 Destroy:<\/p>\n<pre><code class=\"go\">func (docker *Docker) Create(name string, command string, args []string, layers []string, config *Config) (*Container, error) { if docker.Exists(name) { return nil, fmt.Errorf(\"Container %v already exists\", name) } root := path.Join(docker.repository, name) container, err := createContainer(name, root, command, args, layers, config) if err != nil { return nil, err } docker.containers.PushBack(container) return container, nil }  func (docker *Docker) Destroy(container *Container) error { element := docker.getContainerElement(container.Name) if element == nil { return fmt.Errorf(\"Container %v not found - maybe it was already destroyed?\", container.Name) }  if err := container.Stop(); err != nil { return err } if err := os.RemoveAll(container.Root); err != nil { return err }  docker.containers.Remove(element) return nil }  <\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u0432\u0441\u0435 \u043f\u0440\u0435\u0434\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e &#8212; \u043c\u0435\u0442\u043e\u0434 Create \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u043f\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u043e\u043c\u0443 \u0438\u043c\u0435\u043d\u0438, \u0434\u0435\u043b\u0435\u0433\u0438\u0440\u0443\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u0443 createContainer (\u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0444\u0430\u0439\u043b\u0435 <strong>container.go<\/strong>) \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0432 \u0441\u043f\u0438\u0441\u043e\u043a.\u00a0<\/p>\n<p>\u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0435\u043c\u0443 \u043c\u0435\u0442\u043e\u0434 Destroy \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440, \u0443\u0434\u0430\u043b\u044f\u0435\u0442 \u043a\u043e\u0440\u043d\u0435\u0432\u0443\u044e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430, \u0430 \u0437\u0430\u0442\u0435\u043c \u0443\u0434\u0430\u043b\u044f\u0435\u0442 \u0435\u0433\u043e \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430 containers.\u00a0<\/p>\n<p>\u041e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0444\u0430\u0439\u043b\u0430 <strong>docker.go<\/strong> \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u043b\u0438\u0448\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0445\u0435\u043b\u043f\u0435\u0440 \u043c\u0435\u0442\u043e\u0434\u043e\u0432:\u00a0<\/p>\n<ul>\n<li>\n<p>Get &#8212; \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u043f\u043e \u0438\u043c\u0435\u043d\u0438<\/p>\n<\/li>\n<li>\n<p>List &#8212; \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432\u00a0<\/p>\n<\/li>\n<li>\n<p>getContainerElement &#8212; \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0441\u043f\u0438\u0441\u043a\u0430 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432\u00a0<\/p>\n<\/li>\n<li>\n<p>Exists &#8212; \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430\u00a0 \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 \u043f\u043e \u0438\u043c\u0435\u043d\u0438<\/p>\n<\/li>\n<\/ul>\n<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0442\u043e\u0447\u043a\u043e\u0439 \u0431\u0443\u0434\u0435\u0442 \u0444\u0430\u0439\u043b container.go \u0438 \u043c\u0435\u0442\u043e\u0434 createContainer, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0438 \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u043c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435\u043c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432:<\/p>\n<pre><code class=\"go\">func createContainer(name string, root string, command string, args []string, layers []string, config *Config) (*Container, error) { container := &amp;Container{ Name:       name, Root:       root, Path:       command, Args:       args, Config:     config, Filesystem: newFilesystem(path.Join(root, \"rootfs\"), path.Join(root, \"rw\"), layers), State:      newState(),  lxcConfigPath: path.Join(root, \"config.lxc\"), stdout:        newWriteBroadcaster(), stderr:        newWriteBroadcaster(), }  if err := os.Mkdir(root, 0700); err != nil { return nil, err }  if err := container.save(); err != nil { return nil, err } if err := container.generateLXCConfig(); err != nil { return nil, err } return container, nil } <\/code><\/pre>\n<p>\u0412 \u043d\u0430\u0447\u0430\u043b\u0435 \u043c\u0435\u0442\u043e\u0434\u0430 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b Container, \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0432 \u043d\u0435\u0439 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430 \u0434\u043b\u044f \u0443\u0442\u0438\u043b\u0438\u0442\u044b <strong>lxc-start<\/strong>. \u0412 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 newFilesystem \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 filesystem.go \u043f\u0440\u043e\u0441\u0442\u043e \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 Filesystem. \u0427\u0443\u0442\u044c \u043f\u043e\u0437\u0436\u0435 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c filesystem.go \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435.<\/p>\n<pre><code class=\"go\">type Filesystem struct { RootFS string RWPath string Layers []string }  func newFilesystem(rootfs string, rwpath string, layers []string) *Filesystem { return &amp;Filesystem{ RootFS: rootfs, RWPath: rwpath, Layers: layers, } } <\/code><\/pre>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f newState \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 <strong>state.go<\/strong> \u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0443\u044e pid, exitcode, \u0430 \u0442\u0430\u043a \u0436\u0435 \u043c\u044c\u044e\u0442\u0435\u043a\u0441 \u0434\u043b\u044f \u043a\u043e\u043c\u043c\u0443\u043d\u0438\u043a\u0430\u0446\u0438\u0438.<\/p>\n<pre><code class=\"go\">type State struct { Running  bool Pid      int ExitCode int  stateChangeLock *sync.Mutex stateChangeCond *sync.Cond }  func newState() *State { lock := new(sync.Mutex) return &amp;State{ stateChangeLock: lock, stateChangeCond: sync.NewCond(lock), } }<\/code><\/pre>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f newWriteBroadcaster() \u0438\u0437 <strong>utils.go<\/strong> \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0442 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 writeBroadcaster (broadcast pattern) \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0449\u0443\u044e\u0441\u044f \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043f\u043e\u0442\u043e\u043a\u0430\u043c\u0438 stdout \u0438 stderr.<\/p>\n<pre><code class=\"go\">type writeBroadcaster struct { writers *list.List }  func (w *writeBroadcaster) AddWriter(writer io.WriteCloser) { w.writers.PushBack(writer) }  func (w *writeBroadcaster) RemoveWriter(writer io.WriteCloser) { for e := w.writers.Front(); e != nil; e = e.Next() { v := e.Value.(io.Writer) if v == writer { w.writers.Remove(e) return } } }  func (w *writeBroadcaster) Write(p []byte) (n int, err error) { failed := []*list.Element{} for e := w.writers.Front(); e != nil; e = e.Next() { writer := e.Value.(io.Writer) if n, err := writer.Write(p); err != nil || n != len(p) { \/\/ On error, evict the writer failed = append(failed, e) } } \/\/ We cannot remove while iterating, so it has to be done in \/\/ a separate step for _, e := range failed { w.writers.Remove(e) } return len(p), nil }  func (w *writeBroadcaster) Close() error { for e := w.writers.Front(); e != nil; e = e.Next() { writer := e.Value.(io.WriteCloser) writer.Close() } return nil }  func newWriteBroadcaster() *writeBroadcaster { return &amp;writeBroadcaster{list.New()} }<\/code><\/pre>\n<p>\u041c\u0435\u0442\u043e\u0434 save \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u0442 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 Container \u0432 json \u0444\u043e\u0440\u043c\u0430\u0442 \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0432 \u0444\u0430\u0439\u043b, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u0432 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432 \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 restore \u0438 loadContainer, \u043e \u0447\u0435\u043c \u0431\u044b\u043b\u043e \u0443\u043a\u0430\u0437\u0430\u043d\u043e \u0440\u0430\u043d\u0435\u0435.<\/p>\n<pre><code class=\"go\">func (container *Container) save() error { configPath := path.Join(container.Root, \"config.json\") fo, err := os.Create(configPath) if err != nil { return err } defer fo.Close() enc := json.NewEncoder(fo) if err := enc.Encode(container); err != nil { return err } return nil }  func loadContainer(containerPath string) (*Container, error) { configPath := path.Join(containerPath, \"config.json\") fi, err := os.Open(configPath) if err != nil { return nil, err } defer fi.Close() enc := json.NewDecoder(fi) container := &amp;Container{} if err := enc.Decode(container); err != nil { return nil, err } return container, nil } <\/code><\/pre>\n<p>\u041f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u043c\u0443 \u043c\u0435\u0442\u043e\u0434\u0443 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c\u043e\u043c\u0443 \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 createContainer &#8212; generateLXCConfig:<\/p>\n<pre><code class=\"go\">func (container *Container) generateLXCConfig() error { fo, err := os.Create(container.lxcConfigPath) if err != nil { return err } defer fo.Close()  if err := LxcTemplateCompiled.Execute(fo, container); err != nil { return err } return nil } <\/code><\/pre>\n<p>\u041a\u0430\u043a \u0432\u0438\u0434\u0438\u043c, \u0432 \u043d\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f LxcTemplateCompiled.\u00a0\u0427\u0442\u043e\u0431\u044b \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0441 \u043d\u0435\u0439, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0432\u0437\u0433\u043b\u044f\u043d\u0443\u0442\u044c \u043d\u0430 \u0444\u0430\u0439\u043b <strong>lxc_template.go<\/strong>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0448\u0430\u0431\u043b\u043e\u043d \u0434\u043b\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430 lxc:<\/p>\n<details class=\"spoiler\">\n<summary>lxc_template.go<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"go\">const LxcTemplate = ` # hostname {{if .Config.Hostname}} lxc.utsname = {{.Config.Hostname}} {{else}} lxc.utsname = {{.Name}} {{end}} #lxc.aa_profile = unconfined  # network configuration #lxc.network.type = veth #lxc.network.flags = up #lxc.network.link = br0 #lxc.network.name = eth0  # Internal container network interface name #lxc.network.mtu = 1500 #lxc.network.ipv4 = {ip_address}\/{ip_prefix_len}  # root filesystem lxc.rootfs = {{.Filesystem.RootFS}}  # use a dedicated pts for the container (and limit the number of pseudo terminal # available) lxc.pts = 1024  # disable the main console lxc.console = none  # no controlling tty at all lxc.tty = 1  # no implicit access to devices lxc.cgroup.devices.deny = a  # \/dev\/null and zero lxc.cgroup.devices.allow = c 1:3 rwm lxc.cgroup.devices.allow = c 1:5 rwm  # consoles lxc.cgroup.devices.allow = c 5:1 rwm lxc.cgroup.devices.allow = c 5:0 rwm lxc.cgroup.devices.allow = c 4:0 rwm lxc.cgroup.devices.allow = c 4:1 rwm  # \/dev\/urandom,\/dev\/random lxc.cgroup.devices.allow = c 1:9 rwm lxc.cgroup.devices.allow = c 1:8 rwm  # \/dev\/pts\/* - pts namespaces are \"coming soon\" lxc.cgroup.devices.allow = c 136:* rwm lxc.cgroup.devices.allow = c 5:2 rwm  # tuntap lxc.cgroup.devices.allow = c 10:200 rwm  # fuse #lxc.cgroup.devices.allow = c 10:229 rwm  # rtc #lxc.cgroup.devices.allow = c 254:0 rwm   # standard mount point lxc.mount.entry = proc {{.Filesystem.RootFS}}\/proc proc nosuid,nodev,noexec 0 0 lxc.mount.entry = sysfs {{.Filesystem.RootFS}}\/sys sysfs nosuid,nodev,noexec 0 0 lxc.mount.entry = devpts {{.Filesystem.RootFS}}\/dev\/pts devpts newinstance,ptmxmode=0666,nosuid,noexec 0 0 #lxc.mount.entry = varrun {{.Filesystem.RootFS}}\/var\/run tmpfs mode=755,size=4096k,nosuid,nodev,noexec 0 0 #lxc.mount.entry = varlock {{.Filesystem.RootFS}}\/var\/lock tmpfs size=1024k,nosuid,nodev,noexec 0 0 #lxc.mount.entry = shm {{.Filesystem.RootFS}}\/dev\/shm tmpfs size=65536k,nosuid,nodev,noexec 0 0   # drop linux capabilities (apply mainly to the user root in the container) lxc.cap.drop = audit_control audit_write mac_admin mac_override mknod net_raw setfcap setpcap sys_admin sys_boot sys_module sys_nice sys_pacct sys_rawio sys_resource sys_time sys_tty_config  # limits {{if .Config.Ram}} lxc.cgroup.memory.limit_in_bytes = {{.Config.Ram}} {{end}} `  var LxcTemplateCompiled *template.Template  func init() { var err error LxcTemplateCompiled, err = template.New(\"lxc\").Parse(LxcTemplate) if err != nil { panic(err) } } <\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u041e\u043d \u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043c\u043e\u0434\u0443\u043b\u044f, \u0430 \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 generateLXCConfig \u043f\u043e\u0441\u043b\u0435 \u043f\u043e\u0434\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u043d\u0430 \u0434\u0438\u0441\u043a \u0432 \u0444\u0430\u0439\u043b\u0435 config.lxc.\u00a0<\/p>\n<p>\u041f\u043e\u0434\u0432\u0435\u0434\u0435\u043c \u0438\u0442\u043e\u0433: \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 createContainer \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b Container \u0438 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440 Filesystem, State \u0438 writeBroadcaster. \u0414\u0430\u043b\u0435\u0435 \u0432 \u043f\u0430\u043f\u043a\u0435 containers \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f \u0441 \u0438\u043c\u0435\u043d\u0435\u043c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430, \u0432 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 Container \u043f\u043e\u0441\u043b\u0435 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0430 \u0432 json. \u041d\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u043c \u044d\u0442\u0430\u043f\u0435 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b \u0434\u043b\u044f <strong>lxc-start<\/strong>.<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a \u0437\u0430\u043f\u0443\u0441\u043a\u0443 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 Start \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 <strong>container.go<\/strong><\/p>\n<pre><code class=\"go\">func (container *Container) Start() error { if err := container.Filesystem.Mount(); err != nil { return err }  params := []string{ \"-n\", container.Name, \"-f\", container.lxcConfigPath, \"--\", container.Path, } params = append(params, container.Args...)  container.cmd = exec.Command(\"\/usr\/bin\/lxc-start\", params...) container.cmd.Stdout = container.stdout container.cmd.Stderr = container.stderr  if err := container.cmd.Start(); err != nil { return err } container.State.setRunning(container.cmd.Process.Pid) go container.monitor()  \/\/ Wait until we are out of the STARTING state before returning \/\/ \/\/ Even though lxc-wait blocks until the container reaches a given state, \/\/ sometimes it returns an error code, which is why we have to retry. \/\/ \/\/ This is a rare race condition that happens for short lived programs for retries := 0; retries &lt; 3; retries++ { err := exec.Command(\"\/usr\/bin\/lxc-wait\", \"-n\", container.Name, \"-s\", \"RUNNING|STOPPED\").Run() if err == nil { return nil } } return errors.New(\"Container failed to start\") } <\/code><\/pre>\n<p>\u0412 \u043f\u0435\u0440\u0432\u043e\u0439 \u0436\u0435 \u0441\u0442\u0440\u043e\u043a\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043c\u043e\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u043e\u0432\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430. \u0412\u0435\u0441\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u043f\u043e \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 fs \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 <strong>filesystem.go<\/strong>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0432\u0441\u0435\u0433\u043e 50 \u0441\u0442\u0440\u043e\u043a \u043a\u043e\u0434\u0430, \u0442\u0430\u043a \u0447\u0442\u043e \u0438\u043c\u0435\u0435\u0442 \u0441\u043c\u044b\u0441\u043b \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c \u0435\u0433\u043e \u043e\u0441\u0442\u0430\u0432\u0448\u0443\u044e\u0441\u044f \u0447\u0430\u0441\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u0432 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a \u043d\u0435\u043c\u0443.<\/p>\n<pre><code class=\"go\">func (fs *Filesystem) createMountPoints() error { if err := os.Mkdir(fs.RootFS, 0700); err != nil &amp;&amp; !os.IsExist(err) { return err } if err := os.Mkdir(fs.RWPath, 0700); err != nil &amp;&amp; !os.IsExist(err) { return err } return nil }  func (fs *Filesystem) Mount() error { if err := fs.createMountPoints(); err != nil { return err } rwBranch := fmt.Sprintf(\"%v=rw\", fs.RWPath) roBranches := \"\" for _, layer := range fs.Layers { roBranches += fmt.Sprintf(\"%v=ro:\", layer) } branches := fmt.Sprintf(\"br:%v:%v\", rwBranch, roBranches) cmd := exec.Command(\"mount\", \"-t\", \"aufs\", \"-o\", branches, \"none\", fs.RootFS) if err := cmd.Run(); err != nil { return err } return nil }  func (fs *Filesystem) Umount() error { return exec.Command(\"umount\", fs.RootFS).Run() } <\/code><\/pre>\n<p>\u041a\u0430\u043a \u0432\u0438\u0434\u0438\u043c, \u044d\u0442\u043e \u0432\u0441\u0435\u0433\u043e \u043b\u0438\u0448\u044c \u043e\u0431\u0435\u0440\u0442\u043a\u0430 \u043d\u0430\u0434 \u0443\u0442\u0438\u043b\u0438\u0442\u043e\u0439\u00a0 mount. \u041c\u0435\u0442\u043e\u0434 createMountPoints \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u0434\u0432\u0435 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438:<\/p>\n<ul>\n<li>\n<p>Rootfs &#8212; \u0431\u0443\u0434\u0435\u0442 \u0442\u043e\u0447\u043a\u043e\u0439 \u043c\u043e\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0444\u0430\u0439\u043b\u043e\u0432\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430. <\/p>\n<\/li>\n<li>\n<p>RWPath &#8212; \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f \u0441 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c\u044e \u0437\u0430\u043f\u0438\u0441\u0438, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u0443\u0434\u0443\u0442 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c\u0441\u044f \u0432\u0441\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0444\u0430\u0439\u043b\u043e\u0432\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430.  <\/p>\n<\/li>\n<\/ul>\n<p>\u041c\u0435\u0442\u043e\u0434 Mount \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442 \u0441\u0442\u0440\u043e\u043a\u0443 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u0443\u0442\u0438\u043b\u0438\u0442\u0443 <strong>mount<\/strong> \u0441 \u0442\u0438\u043f\u043e\u043c <strong>aufs<\/strong>. \u041c\u0435\u0442\u043e\u0434 Umount \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0440\u0430\u0437\u043c\u043e\u043d\u0442\u0438\u0440\u0443\u0435\u0442 \u0444\u0430\u0439\u043b\u043e\u0432\u0443\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u0443.\u00a0<\/p>\n<p>\u0412\u0441\u0435 \u0441\u043b\u043e\u0438 \u043e\u0431\u0440\u0430\u0437\u0430 (Layers) \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u0441\u043e\u0431\u043e\u0439 \u043f\u0443\u0442\u0438 \u043a \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u043d\u0442\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0441 \u043f\u0440\u0430\u0432\u0430\u043c\u0438 read only \u0432 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u043d\u0443\u044e \u0444\u0430\u0439\u043b\u043e\u0432\u0443\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0432 \u0442\u043e\u0447\u043a\u0435 RootFS, \u0430 \u0432\u0441\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u044f\u0442 \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 RWPath \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044e\u0442\u0441\u044f \u0434\u0430\u0436\u0435 \u043f\u043e\u0441\u043b\u0435 \u0440\u0430\u0437\u043c\u043e\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f. \u0424\u0430\u0439\u043b\u043e\u0432\u0430\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u0430 Aufs \u0438\u043c\u0435\u0435\u0442 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c copy-on-write, \u044d\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u043a\u043e\u0433\u0434\u0430 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0444\u0430\u0439\u043b\u0430 \u043d\u0430\u0445\u043e\u0434\u044f\u0449\u0435\u0433\u043e\u0441\u044f \u0432 read-only \u0441\u043b\u043e\u0435, \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d \u0432 RWPath.\u00a0<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0432\u0435\u0440\u043d\u0435\u043c\u0441\u044f \u043a \u0444\u0443\u043d\u043a\u0446\u0438\u0438 Start \u0438\u0437 container.go. \u041f\u043e\u0441\u043b\u0435 \u043c\u043e\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0444\u0430\u0439\u043b\u043e\u0432\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043e\u043d\u0430 \u043f\u043e\u0434\u0433\u043e\u0442\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0443\u0442\u0438\u043b\u0438\u0442\u0443 lxc-start, \u043f\u0435\u0440\u0435\u0434 \u044d\u0442\u0438\u043c \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u044f \u043f\u043e\u0442\u043e\u043a\u0438 stdout \u0438 stderr. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u0435\u0439 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u0438\u043c\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u0438 \u043f\u0443\u0442\u044c \u043a \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u043c\u0443 \u0444\u0430\u0439\u043b\u0443 config.lxc, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u044b\u043b \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d \u0440\u0430\u043d\u0435\u0435 \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430. \u041f\u043e\u0441\u043b\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0435\u0433\u043e pid \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0432 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 State:<\/p>\n<pre><code class=\"go\">func (s *State) setRunning(pid int) { s.Running = true s.ExitCode = 0 s.Pid = pid s.broadcast() }<\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0433\u043e\u0440\u0443\u0442\u0438\u043d\u0430 monitor, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0436\u0434\u0435\u0442 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430, \u0437\u0430\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u043f\u043e\u0442\u043e\u043a\u0438 stdout \u0438 stderr \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 exitcode \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u0447\u0435\u0440\u0435\u0437 \u043c\u0435\u0442\u043e\u0434 setStopped:<\/p>\n<pre><code class=\"go\">func (container *Container) monitor() { container.cmd.Wait() container.stdout.Close() container.stderr.Close() container.State.setStopped(container.cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()) }  func (s *State) setStopped(exitCode int) { s.Running = false s.Pid = 0 s.ExitCode = exitCode s.broadcast() } <\/code><\/pre>\n<p>\u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434 Stop, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d \u0434\u043b\u044f \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432:<\/p>\n<pre><code class=\"go\">func (container *Container) Stop() error { if container.State.Running { if err := exec.Command(\"\/usr\/bin\/lxc-stop\", \"-n\", container.Name).Run(); err != nil { return err } \/\/FIXME: We should lxc-wait for the container to stop }  if err := container.Filesystem.Umount(); err != nil { \/\/ FIXME: Do not abort, probably already umounted? return nil } return nil }<\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u0442\u043e\u0436\u0435 \u0432\u0441\u0435 \u043f\u0440\u0435\u0434\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e &#8212; \u0435\u0441\u043b\u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0435\u0449\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u0442\u043e \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0435\u0433\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0432\u044b\u0437\u043e\u0432\u0430 \u0443\u0442\u0438\u043b\u0438\u0442\u044b <strong>lxc-stop<\/strong>, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u0440\u0430\u0437\u043c\u043e\u043d\u0442\u0438\u0440\u0443\u0435\u043c \u0444\u0430\u0439\u043b\u043e\u0432\u0443\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u0443.\u00a0<\/p>\n<p>\u041e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u0441\u043e\u0431\u043e\u0439 \u0440\u0430\u0437\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u044b\u0435 \u0445\u0435\u043b\u043f\u0435\u0440\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u044f \u043d\u0435 \u0432\u0438\u0436\u0443 \u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u0441\u043c\u044b\u0441\u043b\u0430 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c.<\/p>\n<h2>\u0417\u0430\u043f\u0443\u0441\u043a \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432<\/h2>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440. \u041a\u0430\u043a \u044f \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u043b \u0432 \u043d\u0430\u0447\u0430\u043b\u0435, \u0432\u0441\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u043d\u0430 \u0447\u0438\u0441\u0442\u043e\u0439 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u043a\u0435 \u0441 Ubuntu 20.04.\u00a0<\/p>\n<p>\u041f\u0435\u0440\u0435\u0434 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435\u043c \u043d\u0443\u0436\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c golang \u0438 lxc, \u0430 \u0442\u0430\u043a \u0436\u0435 \u0441\u043a\u0430\u0447\u0430\u0442\u044c rootfs \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0437\u0430 (\u044f \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c alpine linux).<\/p>\n<pre><code class=\"bash\">sudo apt-get update &amp;&amp; sudo apt-get install -y golang lxc mkdir -p \/home\/vagrant\/docker\/images\/alpine curl https:\/\/dl-cdn.alpinelinux.org\/alpine\/v3.14\/releases\/x86_64\/alpine-minirootfs-3.14.1-x86_64.tar.gz | tar -xz -C \/home\/vagrant\/docker\/images\/alpine<\/code><\/pre>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u0447\u0442\u043e rootfs \u043d\u0430 \u043c\u0435\u0441\u0442\u0435:<\/p>\n<pre><code class=\"bash\">vagrant@ubuntu-focal:~\/engine$ ls \/home\/vagrant\/docker\/images\/alpine\/ bin  dev  etc  home  lib  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var <\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0443\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f, \u0442\u0430\u043a \u043a\u0430\u043a \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u043f\u0446\u0438\u0438 lxc \u043f\u043e\u043c\u0435\u043d\u044f\u043b\u0438\u0441\u044c \u0432 \u043d\u043e\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438, \u0430 \u0442\u0430\u043a \u0436\u0435 \u043f\u043e\u043f\u0440\u0430\u0432\u0438\u043c \u043c\u0435\u0442\u043e\u0434 restore \u0432 docker.go. \u041d\u0438\u0436\u0435 \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d \u043f\u0430\u0442\u0447:<\/p>\n<details class=\"spoiler\">\n<summary>docker.patch<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"diff\">diff --git a\/container.go b\/container.go index 77fd7c0fec..3787ed0278 100644 --- a\/container.go +++ b\/container.go @@ -110,6 +110,7 @@ func (container *Container) Start() error {  params := []string{  \"-n\", container.Name,  \"-f\", container.lxcConfigPath, +\"-F\",  \"--\",  container.Path,  } diff --git a\/docker.go b\/docker.go index 3bdf694664..929fd4cf53 100644 --- a\/docker.go +++ b\/docker.go @@ -81,6 +81,10 @@ func (docker *Docker) restore() error {  }  for _, v := range dir {  container, err := loadContainer(path.Join(docker.repository, v.Name())) +container.State = newState() +container.lxcConfigPath = path.Join(container.Root, \"config.lxc\") +container.stdout  = newWriteBroadcaster() +container.stderr = newWriteBroadcaster()  if err != nil {  fmt.Errorf(\"Failed to load %v: %v\", v.Name(), err)  continue diff --git a\/lxc_template.go b\/lxc_template.go index af9855c663..d13d4cbba5 100644 --- a\/lxc_template.go +++ b\/lxc_template.go @@ -7,9 +7,9 @@ import (  const LxcTemplate = `  # hostname  {{if .Config.Hostname}} -lxc.utsname = {{.Config.Hostname}} +lxc.uts.name = {{.Config.Hostname}}  {{else}} -lxc.utsname = {{.Name}} +lxc.uts.name = {{.Name}}  {{end}}  #lxc.aa_profile = unconfined   @@ -22,17 +22,17 @@ lxc.utsname = {{.Name}}  #lxc.network.ipv4 = {ip_address}\/{ip_prefix_len}    # root filesystem -lxc.rootfs = {{.Filesystem.RootFS}} +lxc.rootfs.path = {{.Filesystem.RootFS}}    # use a dedicated pts for the container (and limit the number of pseudo terminal  # available) -lxc.pts = 1024 +#lxc.pts = 1024    # disable the main console -lxc.console = none +#lxc.console = none    # no controlling tty at all -lxc.tty = 1 +#lxc.tty = 1    # no implicit access to devices  lxc.cgroup.devices.deny = a  <\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043c go mod init docker \u0438 \u043e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u043b\u0438\u0448\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u0443\u044e cli \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0443 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430\u043c\u0438. \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u0430\u043f\u043a\u0443 cli c \u0444\u0430\u0439\u043b\u043e\u043c docker.go \u0438 \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u043c \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u043e\u043c:<\/p>\n<details class=\"spoiler\">\n<summary>cli\/docker.go<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"go\">package main   import ( \"docker\" \"fmt\" \"os\" )   func main() { if len(os.Args) &lt; 3 || (os.Args[1] == \"run\" &amp;&amp; len(os.Args) &lt; 4) { fmt.Println(\"Usage: docker run|destroy container_name [cmd] [args]\") os.Exit(1) }  Docker, err := docker.NewFromDirectory(\"\/home\/vagrant\/docker\")   if err != nil { panic(err) }  name := os.Args[2] container := Docker.Get(name)  switch os.Args[1] { case \"destroy\": if container != nil { err := Docker.Destroy(container) if err != nil { fmt.Println(err) } else { fmt.Printf(\"Container %s has been destroyed\\n\", name) } } else { fmt.Printf(\"Container %s does not exist\\n\", name) } case \"run\": cmd := os.Args[3] args := os.Args[4:] if container == nil { container, err = Docker.Create( name, cmd, args, []string{\"\/home\/vagrant\/docker\/images\/alpine\"}, &amp;docker.Config{}, ) if err != nil { fmt.Println(err) os.Exit(1) } } else { container.Path = cmd container.Args = args } defer container.Stop() output, err := container.Output() if err != nil { fmt.Println(err) } else { fmt.Println(string(output)) } default: fmt.Printf(\"Invalid command %s. Use (run|destroy)\\n\", os.Args[1]) } } <\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u043c \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0443 \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440:<\/p>\n<pre><code class=\"bash\">vagrant@ubuntu-focal:~\/engine\/cli$ go build docker.go vagrant@ubuntu-focal:~\/engine\/cli$ sudo .\/docker run test cat \/etc\/alpine-release 3.14.1 vagrant@ubuntu-focal:~\/engine\/cli$ sudo tree \/home\/vagrant\/docker\/containers\/ \/home\/vagrant\/docker\/containers\/ \u2514\u2500\u2500 test     \u251c\u2500\u2500 config.json     \u251c\u2500\u2500 config.lxc     \u251c\u2500\u2500 rootfs     \u2514\u2500\u2500 rw  3 directories, 2 files<\/code><\/pre>\n<p>\u041a\u0430\u043a \u0432\u0438\u0434\u0438\u043c \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0431\u044b\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0430 \u043f\u0430\u043f\u043a\u0430 \u0441 \u0438\u043c\u0435\u043d\u0435\u043c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u044b\u043b\u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u044b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b \u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u044b \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u0434\u043b\u044f \u0444\u0430\u0439\u043b\u043e\u0432\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b.<\/p>\n<p>\u0417\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u0435\u0449\u0435 \u043e\u0434\u0438\u043d \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0438 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0432 \u043d\u0435\u043c \u0444\u0430\u0439\u043b:<\/p>\n<pre><code class=\"bash\">vagrant@ubuntu-focal:~\/engine\/cli$ sudo .\/docker run test2 touch \/file.txt  vagrant@ubuntu-focal:~\/engine\/cli$ sudo tree \/home\/vagrant\/docker\/containers\/ \/home\/vagrant\/docker\/containers\/ \u251c\u2500\u2500 test \u2502   \u251c\u2500\u2500 config.json \u2502   \u251c\u2500\u2500 config.lxc \u2502   \u251c\u2500\u2500 rootfs \u2502   \u2514\u2500\u2500 rw \u2514\u2500\u2500 test2     \u251c\u2500\u2500 config.json     \u251c\u2500\u2500 config.lxc     \u251c\u2500\u2500 rootfs     \u2514\u2500\u2500 rw         \u2514\u2500\u2500 file.txt  6 directories, 5 files <\/code><\/pre>\n<p>\u0417\u0430\u043f\u0443\u0441\u0442\u0438\u043c \/bin\/sh \u0432 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u043c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435:<\/p>\n<pre><code class=\"bash\">vagrant@ubuntu-focal:~\/engine\/cli$ sudo .\/docker run test2 \/bin\/sh \/ # ls bin       dev       etc       file.txt  home      lib       media     mnt       opt       proc      root      run       sbin      srv       sys       tmp       usr       var <\/code><\/pre>\n<p>\u041f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043c\u043e\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u043e\u0432\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b, \u0442\u0430\u043a \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u043c \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u0444\u0430\u0439\u043b \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043f\u0440\u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440:<\/p>\n<pre><code class=\"bash\">vagrant@ubuntu-focal:~\/engine\/cli$ sudo .\/docker destroy test2 Container test2 has been destroyed vagrant@ubuntu-focal:~\/engine\/cli$ sudo tree \/home\/vagrant\/docker\/containers\/ \/home\/vagrant\/docker\/containers\/ \u2514\u2500\u2500 test     \u251c\u2500\u2500 config.json     \u251c\u2500\u2500 config.lxc     \u251c\u2500\u2500 rootfs     \u2514\u2500\u2500 rw  3 directories, 2 files<\/code><\/pre>\n<p>\u041a\u0430\u043a \u0432\u0438\u0434\u0438\u043c, \u0432\u0441\u0435 \u0444\u0430\u0439\u043b\u044b \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 test2 \u0431\u044b\u043b\u0438 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0443\u0434\u0430\u043b\u0435\u043d\u044b.<\/p>\n<h2>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h2>\n<p>\u0412\u043e\u0442 \u043f\u0440\u0438\u0431\u043b\u0438\u0437\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0442\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b \u0432\u0435\u0441\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b Docker \u043d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u0435\u0433\u043e \u0437\u0430\u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0412 <a href=\"https:\/\/habr.com\/ru\/post\/574750\/\" rel=\"noopener noreferrer nofollow\">\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0435<\/a> \u043c\u044b \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0435\u043c\u0441\u044f \u0432 \u043c\u0430\u0440\u0442 2013, \u043a\u043e\u0433\u0434\u0430 \u043a\u043e\u0434 \u0434\u043e\u043a\u0435\u0440\u0430 \u0432\u043f\u0435\u0440\u0432\u044b\u0435 \u0431\u044b\u043b \u0432\u044b\u043b\u043e\u0436\u0435\u043d \u0432 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439 \u0434\u043e\u0441\u0442\u0443\u043f, \u0438 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043a\u0430\u043a\u0438\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0438 \u0437\u0430 \u044d\u0442\u043e \u0432\u0440\u0435\u043c\u044f.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/573828\/\"> https:\/\/habr.com\/ru\/articles\/573828\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<h2>\u0412\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0435<\/h2>\n<figure class=\"full-width\"><figcaption>The future of Linux Containers<\/figcaption><\/figure>\n<p>20 \u043c\u0430\u0440\u0442\u0430 2013 \u0433\u043e\u0434\u0430 \u043d\u0430 \u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u0438 PyCon 2013, \u0421\u043e\u043b\u043e\u043c\u043e\u043d \u0425\u0430\u0439\u043a\u0441 (CEO \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438 dotCloud) \u0432\u044b\u0441\u0442\u0443\u043f\u0438\u043b \u0441 \u043f\u044f\u0442\u0438\u043c\u0438\u043d\u0443\u0442\u043d\u043e\u0439 \u043f\u0440\u0435\u0437\u0435\u043d\u0442\u0430\u0446\u0438\u0435\u0439 <a href=\"https:\/\/www.youtube.com\/watch?v=wW9CAH9nSLs\" rel=\"noopener noreferrer nofollow\">The future of Linux Containers<\/a>. \u0412 \u043d\u0435\u0439 \u0448\u0438\u0440\u043e\u043a\u043e\u0439 \u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u0432\u043f\u0435\u0440\u0432\u044b\u0435 \u0431\u044b\u043b\u0430 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u044f\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438 dotCloud \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c Docker, \u0430 \u0441\u043f\u0443\u0441\u0442\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0434\u043d\u0435\u0439 \u0435\u0435 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u0431\u044b\u043b \u0432\u044b\u043b\u043e\u0436\u0435\u043d \u0432 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0439 \u0434\u043e\u0441\u0442\u0443\u043f. \u0425\u043e\u0442\u044f \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438 <a href=\"https:\/\/ru.wikipedia.org\/wiki\/LXC\" rel=\"noopener noreferrer nofollow\">LXC<\/a> \u0438 <a href=\"https:\/\/ru.wikipedia.org\/wiki\/Aufs\" rel=\"noopener noreferrer nofollow\">Aufs<\/a>, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0431\u044b\u043b\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0430 \u043f\u0435\u0440\u0432\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f Docker \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043b\u0438 \u0438 \u0430\u043a\u0442\u0438\u0432\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438\u0441\u044c \u0443\u0436\u0435 \u043f\u043e\u0440\u044f\u0434\u043a\u0430 \u043f\u044f\u0442\u0438 \u043b\u0435\u0442, \u043d\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u0435 Docker \u043f\u043e\u0441\u043b\u0443\u0436\u0438\u043b\u043e \u043d\u0430\u0447\u0430\u043b\u043e\u043c \u0441\u0442\u0440\u0435\u043c\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0440\u043e\u0441\u0442\u0430 \u0438 \u044d\u0432\u043e\u043b\u044e\u0446\u0438\u0438 \u0441\u0438\u0441\u0442\u0435\u043c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u0438, \u0447\u0442\u043e \u043a\u0430\u0440\u0434\u0438\u043d\u0430\u043b\u044c\u043d\u043e \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0438\u043b\u043e \u043c\u043d\u043e\u0433\u0438\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u0434\u0435\u043f\u043b\u043e\u0439\u043c\u0435\u043d\u0442\u0430 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e\u0433\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f.<\/p>\n<p>\u042d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435\u0439 \u044f \u0441\u043e\u0431\u0438\u0440\u0430\u044e\u0441\u044c \u043d\u0430\u0447\u0430\u0442\u044c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0446\u0438\u043a\u043b \u043f\u043e\u0441\u0432\u044f\u0449\u0435\u043d\u043d\u044b\u0439 \u0438\u0437\u0443\u0447\u0435\u043d\u0438\u044e \u0440\u0430\u0437\u0432\u0438\u0442\u0438\u044f \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 Docker \u043d\u0430 \u043f\u0440\u043e\u0442\u044f\u0436\u0435\u043d\u0438\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043b\u0435\u0442. \u0412 \u043f\u0435\u0440\u0432\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u043b \u0441\u043e\u0431\u043e\u0439 \u043a\u043e\u0434 \u043d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f git \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u0434\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u044f\u043d\u0432\u0430\u0440\u0435\u043c 2013 \u0433\u043e\u0434\u0430. \u0422\u043e\u0433\u0434\u0430 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 Docker (\u0437\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u0442\u0435\u0441\u0442\u043e\u0432) \u0441\u043e\u0441\u0442\u043e\u044f\u043b \u0432\u0441\u0435\u0433\u043e \u0438\u0437 \u0448\u0435\u0441\u0442\u0438 \u0444\u0430\u0439\u043b\u043e\u0432 \u043e\u0431\u0449\u0438\u043c \u043e\u0431\u044a\u0435\u043c\u043e\u043c ~600 \u0441\u0442\u0440\u043e\u043a \u043a\u043e\u0434\u0430, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0445 \u043d\u0430 \u044f\u0437\u044b\u043a\u0435 Go. \u042d\u0442\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u043f\u043e\u0445\u043e\u0434\u0438\u043b\u043e \u043d\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443\/api, \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0441\u043e\u0441\u0442\u043e\u044f\u043b \u043b\u0438\u0448\u044c \u0432 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438, \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0438, \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0438 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0435 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432. \u041c\u044b \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u043f\u0440\u0438\u043d\u0446\u0438\u043f \u0440\u0430\u0431\u043e\u0442\u044b \u0438 \u0434\u0430\u0436\u0435 \u0441\u043c\u043e\u0436\u0435\u043c \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0441 \u0435\u0435 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440.\u00a0<\/p>\n<p>\u0412\u043e \u0432\u0442\u043e\u0440\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0435\u043c\u0441\u044f \u043d\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0435\u0441\u044f\u0446\u0435\u0432 \u0432\u043f\u0435\u0440\u0435\u0434 &#8212; \u0432 \u043c\u0430\u0440\u0442 2013, \u043a\u043e\u0433\u0434\u0430 \u0434\u043e\u043a\u0435\u0440 \u0431\u044b\u043b \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u043d\u0430 \u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u0438 PyCon. \u041d\u0430 \u0442\u043e\u0442 \u043c\u043e\u043c\u0435\u043d\u0442 \u043e\u043d \u0443\u0436\u0435 \u043e\u0431\u043b\u0430\u0434\u0430\u043b \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u0441\u0435\u043c\u0438 \u0437\u043d\u0430\u043a\u043e\u043c\u044b\u043c\u0438 \u043d\u0430\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c\u0438. \u0410 \u0432 \u0442\u0440\u0435\u0442\u044c\u0435\u0439 \u0447\u0430\u0441\u0442\u0438 \u044f \u043f\u043e\u0441\u0442\u0430\u0440\u0430\u044e\u0441\u044c \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043f\u0435\u0440\u0435\u0445\u043e\u0434 Docker \u0441 LXC \u043d\u0430 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u0443\u044e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443, \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u0435\u0434\u0448\u0438\u0439 \u0433\u043e\u0434\u043e\u043c \u043f\u043e\u0437\u0436\u0435.<\/p>\n<h2>\u0418\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434<\/h2>\n<p>\u0414\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u044f \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Windows 10 c Vagrant \u0438 Ubuntu 20.04. \u0421\u0440\u0430\u0437\u0443 \u0445\u043e\u0447\u0443 \u043f\u0440\u0435\u0434\u0443\u043f\u0440\u0435\u0434\u0438\u0442\u044c, \u0447\u0442\u043e WSL2 \u043d\u0435 \u043f\u043e\u0434\u043e\u0439\u0434\u0435\u0442, \u0442\u0430\u043a \u043a\u0430\u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u043e\u0435 \u044f\u0434\u0440\u043e \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 aufs, \u0442\u0440\u0435\u0431\u0443\u0435\u043c\u0443\u044e \u0432 \u0440\u0430\u043d\u043d\u0438\u0445 \u0432\u0435\u0440\u0441\u0438\u044f\u0445.<\/p>\n<p>\u0412 \u043f\u0435\u0440\u0432\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u043a\u0430\u0447\u0430\u0442\u044c \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 <a href=\"https:\/\/github.com\/docker\/engine.git\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/docker\/engine.git<\/a> \u0438\u043b\u0438 <a href=\"https:\/\/github.com\/moby\/moby.git\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/moby\/moby.git<\/a>.\u00a0\u0421\u043a\u043b\u043e\u043d\u0438\u0440\u0443\u0435\u043c \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0438 \u0432\u0435\u0440\u043d\u0435\u043c\u0441\u044f \u043a \u043d\u0430\u0447\u0430\u043b\u0443 \u0438\u0441\u0442\u043e\u0440\u0438\u0438 (\u0445\u0435\u0448 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u043a\u043e\u043c\u043c\u0438\u0442\u0430 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 <em>git log &#8212;reverse<\/em>).<\/p>\n<pre><code class=\"bash\">cd \/home\/vagrant &amp;&amp; git clone https:\/\/github.com\/docker\/engine.git &amp;&amp; cd .\/engine git checkout -f a27b4b8cb8e838d03a99b6d2b30f76bdaf2f9e5d &amp;&amp; wc -l $(ls -1 | grep -v test) HEAD is now at a27b4b8cb8 Initial commit   203 container.go   112 docker.go    52 filesystem.go    94 lxc_template.go    48 state.go   115 utils.go   624 total <\/code><\/pre>\n<p>\u041d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f (18 \u044f\u043d\u0432\u0430\u0440\u044f 2013 \u0433\u043e\u0434\u0430), \u043a\u043e\u0434 Docker \u0441\u043e\u0441\u0442\u043e\u044f\u043b \u0432\u0441\u0435\u0433\u043e \u0438\u0437 6 \u0444\u0430\u0439\u043b\u043e\u0432 \u043e\u0431\u0449\u0438\u043c \u043e\u0431\u044a\u0435\u043c\u043e\u043c \u0432 624 \u0441\u0442\u0440\u043e\u043a\u0438 \u0438 \u043a\u0430\u043a \u043c\u044b \u0443\u0432\u0438\u0434\u0438\u043c \u0434\u0430\u043b\u0435\u0435, \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u043b \u0441\u043e\u0431\u043e\u0439 \u043b\u0438\u0448\u044c \u043e\u0431\u0435\u0440\u0442\u043a\u0443 \u0438 \u0443\u0434\u043e\u0431\u043d\u043e\u0435 api \u0434\u043b\u044f \u0443\u0442\u0438\u043b\u0438\u0442 <strong>lxc<\/strong> \u0438 <strong>mount<\/strong>.<\/p>\n<p>\u0418\u0442\u0430\u043a, \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a \u0438\u0437\u0443\u0447\u0435\u043d\u0438\u044e \u0441\u0430\u043c\u043e\u0433\u043e \u043a\u043e\u0434\u0430, \u043e\u0442\u043f\u0440\u0430\u0432\u043d\u043e\u0439 \u0442\u043e\u0447\u043a\u043e\u0439 \u0431\u0443\u0434\u0435\u0442 \u0441\u043b\u0443\u0436\u0438\u0442\u044c \u0444\u0430\u0439\u043b <strong>docker.go<\/strong>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u044b \u0444\u0443\u043d\u043a\u0446\u0438\u0438 New \u0438 NewFromDirectory:<\/p>\n<pre><code class=\"go\">type Docker struct { root       string repository string containers *list.List }  func New() (*Docker, error) { return NewFromDirectory(\"\/var\/lib\/docker\") }  func NewFromDirectory(root string) (*Docker, error) { docker := &amp;Docker{ root:       root, repository: path.Join(root, \"containers\"), containers: list.New(), }  if err := os.Mkdir(docker.repository, 0700); err != nil &amp;&amp; !os.IsExist(err) { return nil, err }  if err := docker.restore(); err != nil { return nil, err } return docker, nil } <\/code><\/pre>\n<p>New \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0444\u0430\u0441\u0430\u0434\u043e\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 NewFromDirectory \u0441 \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u044b\u043c \u043f\u0443\u0442\u0435\u043c \/var\/lib\/docker. \u0424\u0443\u043d\u043a\u0446\u0438\u044f NewFromDirectory \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b Docker, \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \u0434\u043b\u044f \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432 (\u0435\u0441\u043b\u0438 \u043e\u043d\u0430 \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442) \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 Docker (\u043f\u0435\u0440\u0435\u0434 \u0447\u0435\u043c \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043c\u0435\u0442\u043e\u0434 restore):<\/p>\n<pre><code class=\"go\">func (docker *Docker) restore() error { dir, err := ioutil.ReadDir(docker.repository) if err != nil { return err } for _, v := range dir { container, err := loadContainer(path.Join(docker.repository, v.Name())) if err != nil { fmt.Errorf(\"Failed to load %v: %v\", v.Name(), err) continue } docker.containers.PushBack(container) } return nil }<\/code><\/pre>\n<p>\u0412 \u043c\u0435\u0442\u043e\u0434\u0435 restore \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432 \u0438\u0437 \u043f\u0430\u043f\u043a\u0438 containers \u0432\u044b\u0437\u043e\u0432\u043e\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u0438 loadContainer. \u041f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0434\u0430\u043d\u043d\u0430\u044f \u043f\u0430\u043f\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u043f\u0443\u0441\u0442\u0430, \u0442\u0430\u043a \u0447\u0442\u043e \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0435\u0442. \u041c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0434\u0430\u043d\u043d\u044b\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043f\u043e\u0437\u0436\u0435, \u043a\u043e\u0433\u0434\u0430 \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a \u0444\u0430\u0439\u043b\u0443 <strong>container.go<\/strong>.<\/p>\n<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u044e\u0449\u0438\u0435 \u043d\u0430\u0441 \u043c\u0435\u0442\u043e\u0434\u044b \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 docker.go \u044d\u0442\u043e Create \u0438 Destroy:<\/p>\n<pre><code class=\"go\">func (docker *Docker) Create(name string, command string, args []string, layers []string, config *Config) (*Container, error) { if docker.Exists(name) { return nil, fmt.Errorf(\"Container %v already exists\", name) } root := path.Join(docker.repository, name) container, err := createContainer(name, root, command, args, layers, config) if err != nil { return nil, err } docker.containers.PushBack(container) return container, nil }  func (docker *Docker) Destroy(container *Container) error { element := docker.getContainerElement(container.Name) if element == nil { return fmt.Errorf(\"Container %v not found - maybe it was already destroyed?\", container.Name) }  if err := container.Stop(); err != nil { return err } if err := os.RemoveAll(container.Root); err != nil { return err }  docker.containers.Remove(element) return nil }  <\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u0432\u0441\u0435 \u043f\u0440\u0435\u0434\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e &#8212; \u043c\u0435\u0442\u043e\u0434 Create \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u043f\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u043e\u043c\u0443 \u0438\u043c\u0435\u043d\u0438, \u0434\u0435\u043b\u0435\u0433\u0438\u0440\u0443\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u0443 createContainer (\u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0444\u0430\u0439\u043b\u0435 <strong>container.go<\/strong>) \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0432 \u0441\u043f\u0438\u0441\u043e\u043a.\u00a0<\/p>\n<p>\u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0435\u043c\u0443 \u043c\u0435\u0442\u043e\u0434 Destroy \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440, \u0443\u0434\u0430\u043b\u044f\u0435\u0442 \u043a\u043e\u0440\u043d\u0435\u0432\u0443\u044e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430, \u0430 \u0437\u0430\u0442\u0435\u043c \u0443\u0434\u0430\u043b\u044f\u0435\u0442 \u0435\u0433\u043e \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430 containers.\u00a0<\/p>\n<p>\u041e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0444\u0430\u0439\u043b\u0430 <strong>docker.go<\/strong> \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u043b\u0438\u0448\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0445\u0435\u043b\u043f\u0435\u0440 \u043c\u0435\u0442\u043e\u0434\u043e\u0432:\u00a0<\/p>\n<ul>\n<li>\n<p>Get &#8212; \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u043f\u043e \u0438\u043c\u0435\u043d\u0438<\/p>\n<\/li>\n<li>\n<p>List &#8212; \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432\u00a0<\/p>\n<\/li>\n<li>\n<p>getContainerElement &#8212; \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0441\u043f\u0438\u0441\u043a\u0430 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432\u00a0<\/p>\n<\/li>\n<li>\n<p>Exists &#8212; \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430\u00a0 \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 \u043f\u043e \u0438\u043c\u0435\u043d\u0438<\/p>\n<\/li>\n<\/ul>\n<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0442\u043e\u0447\u043a\u043e\u0439 \u0431\u0443\u0434\u0435\u0442 \u0444\u0430\u0439\u043b container.go \u0438 \u043c\u0435\u0442\u043e\u0434 createContainer, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0438 \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u043c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435\u043c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432:<\/p>\n<pre><code class=\"go\">func createContainer(name string, root string, command string, args []string, layers []string, config *Config) (*Container, error) { container := &amp;Container{ Name:       name, Root:       root, Path:       command, Args:       args, Config:     config, Filesystem: newFilesystem(path.Join(root, \"rootfs\"), path.Join(root, \"rw\"), layers), State:      newState(),  lxcConfigPath: path.Join(root, \"config.lxc\"), stdout:        newWriteBroadcaster(), stderr:        newWriteBroadcaster(), }  if err := os.Mkdir(root, 0700); err != nil { return nil, err }  if err := container.save(); err != nil { return nil, err } if err := container.generateLXCConfig(); err != nil { return nil, err } return container, nil } <\/code><\/pre>\n<p>\u0412 \u043d\u0430\u0447\u0430\u043b\u0435 \u043c\u0435\u0442\u043e\u0434\u0430 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b Container, \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0432 \u043d\u0435\u0439 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430 \u0434\u043b\u044f \u0443\u0442\u0438\u043b\u0438\u0442\u044b <strong>lxc-start<\/strong>. \u0412 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 newFilesystem \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 filesystem.go \u043f\u0440\u043e\u0441\u0442\u043e \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 Filesystem. \u0427\u0443\u0442\u044c \u043f\u043e\u0437\u0436\u0435 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c filesystem.go \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435.<\/p>\n<pre><code class=\"go\">type Filesystem struct { RootFS string RWPath string Layers []string }  func newFilesystem(rootfs string, rwpath string, layers []string) *Filesystem { return &amp;Filesystem{ RootFS: rootfs, RWPath: rwpath, Layers: layers, } } <\/code><\/pre>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f newState \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 <strong>state.go<\/strong> \u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0443\u044e pid, exitcode, \u0430 \u0442\u0430\u043a \u0436\u0435 \u043c\u044c\u044e\u0442\u0435\u043a\u0441 \u0434\u043b\u044f \u043a\u043e\u043c\u043c\u0443\u043d\u0438\u043a\u0430\u0446\u0438\u0438.<\/p>\n<pre><code class=\"go\">type State struct { Running  bool Pid      int ExitCode int  stateChangeLock *sync.Mutex stateChangeCond *sync.Cond }  func newState() *State { lock := new(sync.Mutex) return &amp;State{ stateChangeLock: lock, stateChangeCond: sync.NewCond(lock), } }<\/code><\/pre>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f newWriteBroadcaster() \u0438\u0437 <strong>utils.go<\/strong> \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0442 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 writeBroadcaster (broadcast pattern) \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0449\u0443\u044e\u0441\u044f \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043f\u043e\u0442\u043e\u043a\u0430\u043c\u0438 stdout \u0438 stderr.<\/p>\n<pre><code class=\"go\">type writeBroadcaster struct { writers *list.List }  func (w *writeBroadcaster) AddWriter(writer io.WriteCloser) { w.writers.PushBack(writer) }  func (w *writeBroadcaster) RemoveWriter(writer io.WriteCloser) { for e := w.writers.Front(); e != nil; e = e.Next() { v := e.Value.(io.Writer) if v == writer { w.writers.Remove(e) return } } }  func (w *writeBroadcaster) Write(p []byte) (n int, err error) { failed := []*list.Element{} for e := w.writers.Front(); e != nil; e = e.Next() { writer := e.Value.(io.Writer) if n, err := writer.Write(p); err != nil || n != len(p) { \/\/ On error, evict the writer failed = append(failed, e) } } \/\/ We cannot remove while iterating, so it has to be done in \/\/ a separate step for _, e := range failed { w.writers.Remove(e) } return len(p), nil }  func (w *writeBroadcaster) Close() error { for e := w.writers.Front(); e != nil; e = e.Next() { writer := e.Value.(io.WriteCloser) writer.Close() } return nil }  func newWriteBroadcaster() *writeBroadcaster { return &amp;writeBroadcaster{list.New()} }<\/code><\/pre>\n<p>\u041c\u0435\u0442\u043e\u0434 save \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u0442 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 Container \u0432 json \u0444\u043e\u0440\u043c\u0430\u0442 \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0432 \u0444\u0430\u0439\u043b, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u0432 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432 \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 restore \u0438 loadContainer, \u043e \u0447\u0435\u043c \u0431\u044b\u043b\u043e \u0443\u043a\u0430\u0437\u0430\u043d\u043e \u0440\u0430\u043d\u0435\u0435.<\/p>\n<pre><code class=\"go\">func (container *Container) save() error { configPath := path.Join(container.Root, \"config.json\") fo, err := os.Create(configPath) if err != nil { return err } defer fo.Close() enc := json.NewEncoder(fo) if err := enc.Encode(container); err != nil { return err } return nil }  func loadContainer(containerPath string) (*Container, error) { configPath := path.Join(containerPath, \"config.json\") fi, err := os.Open(configPath) if err != nil { return nil, err } defer fi.Close() enc := json.NewDecoder(fi) container := &amp;Container{} if err := enc.Decode(container); err != nil { return nil, err } return container, nil } <\/code><\/pre>\n<p>\u041f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u043c\u0443 \u043c\u0435\u0442\u043e\u0434\u0443 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c\u043e\u043c\u0443 \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 createContainer &#8212; generateLXCConfig:<\/p>\n<pre><code class=\"go\">func (container *Container) generateLXCConfig() error { fo, err := os.Create(container.lxcConfigPath) if err != nil { return err } defer fo.Close()  if err := LxcTemplateCompiled.Execute(fo, container); err != nil { return err } return nil } <\/code><\/pre>\n<p>\u041a\u0430\u043a \u0432\u0438\u0434\u0438\u043c, \u0432 \u043d\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f LxcTemplateCompiled.\u00a0\u0427\u0442\u043e\u0431\u044b \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0441 \u043d\u0435\u0439, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0432\u0437\u0433\u043b\u044f\u043d\u0443\u0442\u044c \u043d\u0430 \u0444\u0430\u0439\u043b <strong>lxc_template.go<\/strong>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-403536","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/403536","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=403536"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/403536\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=403536"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=403536"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=403536"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}