{"id":93,"date":"2017-03-29T22:56:11","date_gmt":"2017-03-29T14:56:11","guid":{"rendered":"http:\/\/www.jsjs.org\/?p=93"},"modified":"2017-03-29T22:56:11","modified_gmt":"2017-03-29T14:56:11","slug":"jenkinsansiblegitlab%e8%87%aa%e5%8a%a8%e5%8c%96%e9%83%a8%e7%bd%b2%e4%b8%89%e5%89%91%e5%ae%a2","status":"publish","type":"post","link":"https:\/\/blog.jsjs.org\/?p=93","title":{"rendered":"Jenkins+Ansible+Gitlab\u81ea\u52a8\u5316\u90e8\u7f72\u4e09\u5251\u5ba2"},"content":{"rendered":"<p>\u6700\u8fd1\u4e00\u76f4\u5728\u5b66\u4e60<a class=\"tag_link\" title=\"\u67e5\u770bAnsible\u4e2d\u7684\u5168\u90e8\u6587\u7ae0\" href=\"http:\/\/www.showerlee.com\/archives\/tag\/ansible\">Ansible<\/a>\u7684\u4e00\u4e9bplaybook\u7684\u5199\u6cd5, \u6240\u4ee5\u4e00\u76f4\u6ca1\u6709\u600e\u4e48\u66f4\u65b0, \u60f3\u5230\u76ee\u524d\u5927\u5bb6\u5bf9\u8bf8\u5982saltstack, docker, <a class=\"tag_link\" title=\"\u67e5\u770bAnsible\u4e2d\u7684\u5168\u90e8\u6587\u7ae0\" href=\"http:\/\/www.showerlee.com\/archives\/tag\/ansible\">Ansible<\/a>\u7b49\u81ea\u52a8\u5316\u90e8\u7f72\u76f8\u5173\u7684\u5de5\u5177\u5f88\u611f\u5174\u8da3, \u4f46\u53c8\u82e6\u4e8e\u6ca1\u6709\u53ef\u5b66\u4e60\u7684\u4e2d\u6587\u5b9e\u4f8b, \u8fd9\u91cc\u6211\u5c31\u628a\u6211\u8fd9\u51e0\u4e2a\u6708\u6240\u63a5\u89e6\u5230\u76ee\u524d\u56fd\u5916\u6bd4\u8f83\u6d41\u884c\u7684\u90e8\u7f72\u7ecf\u9a8c\u7ed9\u5927\u5bb6\u5206\u4eab\u4e00\u4e0b.<\/p>\n<p>\u9996\u5148\u7ed9\u5927\u5bb6\u4ecb\u7ecd\u7684\u662f<a class=\"tag_link\" title=\"\u67e5\u770bAnsible\u4e2d\u7684\u5168\u90e8\u6587\u7ae0\" href=\"http:\/\/www.showerlee.com\/archives\/tag\/ansible\">Ansible<\/a>, \u6069, \u91cd\u8981\u7684\u95ee\u9898\u8bf4\u4e09\u904d, \u4e0d\u662fSaltstack, <a class=\"tag_link\" title=\"\u67e5\u770bAnsible\u4e2d\u7684\u5168\u90e8\u6587\u7ae0\" href=\"http:\/\/www.showerlee.com\/archives\/tag\/ansible\">Ansible<\/a>\u4f5c\u4e3a\u4e00\u4e2apython\u5199\u7684\u81ea\u52a8\u5316\u90e8\u7f72\u5de5\u5177, \u786e\u5b9e\u8f83\u4e4b\u524d\u6211\u6240\u63a5\u89e6\u7684Chef, saltstack, puppet\u66f4\u6709\u81ea\u5df1\u7684\u4e00\u4e9b\u4f18\u52bf, \u9996\u5148\u5c31\u662fagentless, \u65e0\u9700\u5728Linux client\u5b89\u88c5\u4efb\u4f55\u670d\u52a1\u5373\u53ef\u65e0\u7f1d\u8fde\u63a5Linux default ssh\u7aef\u53e3\u8fdb\u884c\u90e8\u7f72(windows\u9700\u8981\u5b89\u88c5winrm \u5f00\u542fssh\u670d\u52a1), \u8fd9\u70b9\u5176\u5b9e\u6211\u89c9\u5f97\u975e\u5e38\u91cd\u8981, \u53ef\u4ee5\u60f3\u8c61\u5f88\u591a\u516c\u53f8\u672c\u8eab\u662f\u5bf9network\u7ba1\u7406\u975e\u5e38\u4e25\u683c\u7684, \u5728\u90e8\u7f72\u4e00\u4e2a\u4ea7\u54c1\u7684\u540c\u65f6\u4f60\u9700\u8981\u8003\u8651\u5f88\u591a\u65f6\u95f4\u6210\u672c, \u4f7f\u7528\u5176\u4ed6\u90e8\u7f72\u5de5\u5177\u672c\u8eab\u975e\u5e38\u68d8\u624b\u7684\u95ee\u9898\u5c31\u662f\u53bb\u7533\u8bf7\u5f00\u7aef\u53e3, client\u91cf\u5c11\u7684\u8bdd, \u6211\u4eec\u53ef\u4ee5\u53bb\u7b49, \u591a\u7684\u8bdd\u672c\u8eab\u4f60\u53bbrequest, waiting, unblock port\u7b49\u7b49long long process&#8230;. \u6700\u540e\u4f1a\u8017\u8d39\u5f88\u957f\u65f6\u95f4. \u8fd9\u4e2a\u5bf9\u5f88\u591a\u4ea7\u54c1\u672c\u8eab\u5c31\u662f\u5f88\u81f4\u547d\u7684. \u4e0d\u63a8\u8350Saltstack\u7684\u539f\u56e0\u4e5f\u662f\u56e0\u4e3a\u5176\u9700\u8981\u5728\u6bcf\u53f0agent\u9010\u4e00\u53bb\u5b89\u88c5client service\u5e76\u6d4b\u8bd5, \u8fd9\u672c\u8eab\u5c31\u4f1a\u8017\u8d39\u4e00\u4e9b\u65f6\u95f4\u6210\u672c.<\/p>\n<p>\u5176\u4ed6\u5462? \u5176\u5b9e\u6211\u89c9\u5f97\u5c31\u662f\u5bb9\u6613\u4e0a\u624b, \u8bed\u6cd5\u7b80\u5355, \u6709\u73b0\u6210\u6a21\u677f\u8ba9\u4f60\u53bb\u5b66\u4e60, \u52a0\u4e4b\u662f\u6211\u4eec\u975e\u5e38\u559c\u7231\u7684python\u8bed\u6cd5, why not?<\/p>\n<p>Jenkins\u4e0d\u7528\u6211\u591a\u8bf4, \u4f30\u8ba1\u61c2\u884c\u7684\u4eba\u90fd\u5728\u7528\u5b83, \u5f00\u6e90, \u8f7b\u91cf\u7ea7, \u517c\u5bb9\u6027\u548c\u6269\u5c55\u6027\u5f3a, \u76f4\u89c2\u7684GUI\u7ba1\u7406\u8fd9\u90fd\u662f\u5b83\u7684\u4f18\u52bf, \u914d\u5408<a class=\"tag_link\" title=\"\u67e5\u770bAnsible\u4e2d\u7684\u5168\u90e8\u6587\u7ae0\" href=\"http:\/\/www.showerlee.com\/archives\/tag\/ansible\">Ansible<\/a>\u6211\u89c9\u5f97\u7528\u8d77\u6765\u4f1a\u975e\u5e38easy going.<\/p>\n<p>\u6700\u540e\u63d0\u4e00\u4e0bGitlab, \u4e3a\u4ec0\u4e48\u8981\u7528Gitlab? \u4ed6\u4f5c\u4e3a\u4e00\u4e2a\u4ee3\u7801\u7248\u672c\u63a7\u5236\u7cfb\u7edf\u548c\u90e8\u7f72\u6709\u4ec0\u4e48\u5173\u7cfb\u5462? \u5176\u5b9e\u8fd9\u91cc\u5c31\u6d89\u53ca\u4e00\u4e2a\u6211\u4eecAnsible playbook\u7ba1\u7406\u95ee\u9898, \u8bd5\u60f3\u6211\u4eec\u9700\u8981\u7ef4\u62a4\u4e00\u4e2a\u516c\u53f8\u5e9e\u5927\u7684server\u96c6\u7fa4, \u6211\u4eec\u6240\u6709\u9700\u8981\u90e8\u7f72\u7684\u673a\u5668\u6216\u8005\u4ea7\u54c1\u4f1a\u5bf9\u5e94\u6211\u4eec\u76f8\u5bf9\u7684\u90e8\u7f72\u811a\u672c, \u6211\u4eec\u4f7f\u7528\u7684Ansible playbook\u5982\u679c\u53ea\u662f\u4fdd\u5b58\u5728Ansible Server\u7684\u5177\u4f53\u67d0\u4e2a\u76ee\u5f55, \u8fd9\u672c\u8eab\u5c31\u4e0d\u4fbf\u4e8e\u6211\u4eec\u8fdb\u884c\u7f16\u5199\u7ef4\u62a4\u66f4\u65b0(\u60f3\u60f3\u6bcf\u6b21\u90fd\u8dd1\u5230\u8fdc\u7a0b\u53bb\u7f16\u5199playbook\u6216\u8005\u6bcf\u6b21\u5728\u672c\u5730\u7f16\u5199\u597d\u540e\u518dupload\u5230\u8fdc\u7a0b\u6211\u90fd\u4f1a\u8111\u8865\u6570\u4ee5\u4e07\u8ba1\u7684\u8349\u6ce5\u9a6c\u4ece\u6211\u773c\u524d\u547c\u5578\u800c\u6765).<\/p>\n<p>\u8fd9\u91ccGitlab\u5c31\u7ed9\u6211\u4eec\u63d0\u4f9b\u4e00\u4e2a\u975e\u5e38\u65b9\u4fbf\u4ee5\u53ca\u76f4\u89c2\u7684Playbook management. \u6211\u4eec\u9700\u8981\u505a\u7684\u5176\u5b9e\u5c31\u662f\u5728Gitlab\u53bb\u5efa\u7acb\u4e00\u4e2a\u5bf9\u5e94\u4ea7\u54c1\u6216\u8005server\u7684playbook\u4ed3\u5e93, \u7136\u540e\u6211\u4eec\u5728\u672c\u5730\u5199\u597d\u540e\u76f4\u63a5commit\u5230\u8fd9\u4e2a\u4ed3\u5e93, \u6700\u540e\u5728\u90e8\u7f72\u7684\u65f6\u5019, \u53bb\u8ba9Jenkins pull\u8fd9\u4e2aplaybook\u5230\u5176workspace, \u5e76\u4f5c\u4e3a\u4e00\u4e2aJob\u53bbrun\u8fd9\u4e2aplaybook, \u8fd9\u6837\u662f\u4e0d\u662f\u5f88\u89c4\u8303, \u800c\u4e14\u4fbf\u4e8e\u7ba1\u7406?<\/p>\n<p>\u5f53\u7136Ansible\u672c\u8eab\u4f01\u4e1a\u7248Tower\u4e5f\u4f1a\u63d0\u4f9b\u4e00\u4e2a\u7c7b\u4f3c\u7ba1\u7406\u5e76\u7ef4\u62a4playbook\u4ee5\u53ca\u76d1\u63a7ansible\u672c\u8eabrunning process\u7684GUI\u7ba1\u7406\u7cfb\u7edf, \u7528\u8d77\u6765\u4e5f\u5f88\u4e0d\u9519, \u4f46\u4f5c\u4e3a\u6536\u8d39\u7248\u672c, \u6211\u4eec\u5728\u8fd9\u91cc\u5c31\u4e0d\u505a\u8fc7\u591a\u9610\u8ff0\u4e86.<\/p>\n<p>\u8fd9\u91cc\u6211\u63a8\u8350Jenkins\u548cAnsible\u53ef\u4ee5\u5b89\u88c5\u5230\u540c\u4e00\u4e2a\u73af\u5883\u4f5c\u4e3a\u90e8\u7f72server, Gitlab\u4f5c\u4e3a\u7248\u672c\u63a7\u5236\u7cfb\u7edf\u53ef\u5355\u72ec\u90e8\u7f72\u5728\u53e6\u4e00\u53f0server.<\/p>\n<p>\u603b\u7ed3:<\/p>\n<p>Jenkins\u9996\u5148\u4eceGitlab\u53bb\u6293\u53d6\u6211\u4eec\u5199\u597d\u7684\u5177\u4f53\u4ea7\u54c1\u7684playbook, \u5e76\u4f7f\u7528virtualenv\u4e0b\u7684Ansible\u76f8\u5173\u547d\u4ee4, \u4fdd\u8bc1\u6211\u4eec\u5728\u4e00\u4e2aclean\u7684\u73af\u5883\u4e0b\u4f7f\u7528stable version\u53bb\u6279\u91cf\u90e8\u7f72\u6211\u4eec\u7684\u4ea7\u54c1\u5230\u8fdc\u7a0bclient.<\/p>\n<p>Let&#8217;s go&#8230;..<\/p>\n<p>\u4e00. \u5b89\u88c5\u73af\u5883<\/p>\n<p>System: CentOS 6.7 x64 (deploy.example.com)<\/p>\n<p>Jenkins:\u00a0Jenkins ver. 1.650<\/p>\n<p>Ansible: Ansible 2.1.0<\/p>\n<p>Gitlab:\u00a0GitLab 7.14.3<\/p>\n<p>\u4e8c. Jenkins\u914d\u7f6e<\/p>\n<p>\u6211\u4eec\u521b\u5efadeploy\u7528\u6237\u4f5c\u4e3ajenkins_user, workspace\u4e3adeploy\u5bb6\u76ee\u5f55\u4e0b\u7684jenkins\u76ee\u5f55.<\/p>\n<p># su &#8211; root<\/p>\n<p># adduser deploy<\/p>\n<p># wget -O \/etc\/yum.repos.d\/jenkins.repo <a href=\"http:\/\/pkg.jenkins-ci.org\/redhat\/jenkins.repo\" rel=\"nofollow\">http:\/\/pkg.jenkins-ci.org\/redhat\/jenkins.repo<\/a><\/p>\n<p># rpm &#8211;import <a href=\"https:\/\/jenkins-ci.org\/redhat\/jenkins-ci.org.key\" rel=\"nofollow\">https:\/\/jenkins-ci.org\/redhat\/jenkins-ci.org.key<\/a><\/p>\n<p># yum install jenkins -y<\/p>\n<p># vi\u00a0\/etc\/sysconfig\/jenkins<\/p>\n<pre class=\"prettyprint lang-bsh\">...\nJENKINS_HOME=\"\/home\/deploy\/jenkins\"\nJENKINS_USER=\"deploy\"\n...<\/pre>\n<p># service jenkins start<\/p>\n<p>\u6d4f\u89c8\u5668\u8bbf\u95eeJenkins\u9875\u9762<\/p>\n<p><a href=\"http:\/\/deploy.example.com:8080\/\" rel=\"nofollow\">http:\/\/deploy.example.com:8080<\/a><\/p>\n<p>\u5b89\u88c5\u5b8c\u6210, \u4ee5\u4e0b\u662f\u6211\u5df2\u7ecf\u914d\u7f6e\u597d\u7684\u4e00\u4e9bJenkins\u00a0Job.<\/p>\n<p><a href=\"http:\/\/www.showerlee.com\/wp-content\/uploads\/2016\/03\/QQ20160311-0.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-1884\" src=\"http:\/\/www.showerlee.com\/wp-content\/uploads\/2016\/03\/QQ20160311-0-1024x338.png\" alt=\"QQ20160311-0\" width=\"1024\" height=\"338\" \/><\/a><\/p>\n<p>\u8fd9\u91cc\u6211\u4eec\u4f7f\u7528\u4e00\u4e2a\u56fd\u5185PHP\u7f51\u7ad9\u6a21\u677fphpcms\u4f5c\u4e3a\u6211\u4eec\u9700\u8981\u90e8\u7f72\u7684\u4ea7\u54c1\u8fdb\u884c\u672c\u6b21\u8303\u4f8b\u6f14\u793a, \u5728\u8fdb\u884c\u6700\u7ec8\u7684Build\u524d\u6211\u4eec\u9700\u8981\u505a\u4e00\u4e9b\u51c6\u5907\u5de5\u4f5c, \u7a0d\u540e\u6211\u4eec\u4f1a\u56de\u5230\u8fd9\u4e2a\u754c\u9762.<\/p>\n<p>\u4e09. Ansible\u914d\u7f6e<\/p>\n<p>\u8fd9\u91cc\u6211\u4eec\u9700\u8981\u914d\u7f6evirtualenv\u53bb\u9694\u79bb\u6211\u4eecansible\u7684\u53d1\u884c\u7248\u672c\u4e3a\u6700\u65b0\u7248\u672c2.1.0, \u9ed8\u8ba4pip\u6216\u8005yum\u5b89\u88c5\u76841.9\u7248\u672c\u56e0\u4e3aBUG\u4ee5\u53ca\u5bf9windows\u4e0d\u517c\u5bb9\u7684\u539f\u56e0, \u8fd9\u91cc\u4e0d\u63a8\u8350\u4f7f\u7528.<\/p>\n<p>\u914d\u7f6e\u6b65\u9aa4\u4f20\u9001\u95e8:\u00a0<a href=\"http:\/\/www.showerlee.com\/archives\/1862\" target=\"_blank\" rel=\"noopener\">http:\/\/www.showerlee.com\/archives\/1862<\/a><\/p>\n<p>Ansible-playbook\u8303\u4f8b\u4f20\u9001\u95e8:\u00a0<a href=\"http:\/\/www.showerlee.com\/archives\/1649\" target=\"_blank\" rel=\"noopener\">http:\/\/www.showerlee.com\/archives\/1649<\/a><\/p>\n<p>\u56db. Gitlab\u914d\u7f6e<\/p>\n<p>\u90e8\u7f72\u5e76\u4f7f\u7528\u4f20\u9001\u95e8:\u00a0<a href=\"http:\/\/www.showerlee.com\/archives\/1285\" target=\"_blank\" rel=\"noopener\">http:\/\/www.showerlee.com\/archives\/1285<\/a><\/p>\n<p>\u6211\u4eec\u6700\u7ec8\u4f1a\u521b\u5efa\u4e00\u4e2aansible playbook\u4ed3\u5e93\u00a0git@git.example.cn:showerlee\/Ansible-showerlee.git, \u5e76\u5728\u672c\u5730\u7f16\u5199\u597d\u6211\u4eec\u7684\u89c4\u5219, \u6700\u7ec8commit\u5230\u8fd9\u4e2a\u4ed3\u5e93, \u4ee5\u4fbfJenkins\u53bb\u8c03\u7528\u6211\u4eec\u7684\u90e8\u7f72\u89c4\u5219.<\/p>\n<p>\u8fd9\u91cc\u535a\u4e3b\u5355\u72ecclone\u51fa\u6765\u4e00\u4efd\u90e8\u7f72phpcms\u7684playbook\u4ed3\u5e93, \u7b97\u662f\u7ed9\u5927\u5bb6\u7684\u798f\u5229:<\/p>\n<p><a href=\"https:\/\/git.yanwenbo.cn\/showerlee\/leon-playbook-phpcms1.1\" rel=\"nofollow\">https:\/\/git.yanwenbo.cn\/showerlee\/leon-playbook-phpcms1.1<\/a><\/p>\n<p><a href=\"http:\/\/www.showerlee.com\/wp-content\/uploads\/2016\/03\/QQ20160311-2.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-1885\" src=\"http:\/\/www.showerlee.com\/wp-content\/uploads\/2016\/03\/QQ20160311-2-1024x500.png\" alt=\"QQ20160311-2\" width=\"1024\" height=\"500\" \/><\/a><\/p>\n<p><a href=\"http:\/\/www.showerlee.com\/wp-content\/uploads\/2016\/03\/QQ20160311-3.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-1886\" src=\"http:\/\/www.showerlee.com\/wp-content\/uploads\/2016\/03\/QQ20160311-3-1024x250.png\" alt=\"QQ20160311-3\" width=\"1024\" height=\"250\" \/><\/a><\/p>\n<p><a href=\"http:\/\/www.showerlee.com\/wp-content\/uploads\/2016\/03\/QQ20160311-4.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-1887\" src=\"http:\/\/www.showerlee.com\/wp-content\/uploads\/2016\/03\/QQ20160311-4-1024x274.png\" alt=\"QQ20160311-4\" width=\"1024\" height=\"274\" \/><\/a><\/p>\n<p>\u4e94.\u6700\u7ec8\u90e8\u7f72<\/p>\n<p>\u51c6\u5907\u5de5\u4f5c\u5b8c\u6bd5, \u6211\u4eec\u63a5\u4e0b\u6765\u7ed9\u5927\u5bb6\u4ecb\u7ecdJenkins Job\u914d\u7f6e.<\/p>\n<p>1.\u521b\u5efa\u4e00\u4e2anew item<\/p>\n<p><a href=\"http:\/\/www.showerlee.com\/wp-content\/uploads\/2016\/03\/QQ20160311-5.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1888\" src=\"http:\/\/www.showerlee.com\/wp-content\/uploads\/2016\/03\/QQ20160311-5.png\" alt=\"QQ20160311-5\" width=\"354\" height=\"313\" \/><\/a><\/p>\n<p>2. \u521b\u5efa\u4e00\u4e2afreestyle Job, \u547d\u540d\u89c4\u5219&#8221;\u4ea7\u54c1\u540d-\u73af\u5883&#8221;, \u8fd9\u91cc\u6211\u4eec\u4e3aPhpcms-Dev<\/p>\n<p><a href=\"http:\/\/www.showerlee.com\/wp-content\/uploads\/2016\/03\/QQ20160311-6.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-1889\" src=\"http:\/\/www.showerlee.com\/wp-content\/uploads\/2016\/03\/QQ20160311-6-1024x306.png\" alt=\"QQ20160311-6\" width=\"1024\" height=\"306\" \/><\/a><\/p>\n<p>3. Job\u914d\u7f6e<\/p>\n<p>1). \u5b9a\u5236Build\u53c2\u6570.<\/p>\n<p>\u8fd9\u91ccDynamic Choice Parameter\u7528\u6765\u901a\u8fc7Groovy\u811a\u672c\u6765\u6293\u53d6\u8fd9\u4e2agit\u4ed3\u5e93\u7684\u6240\u6709branch, \u5e76\u4f5c\u4e3a\u4e00\u4e2a\u591a\u9009\u9879, \u65b9\u4fbf\u6211\u4eec\u5728\u6700\u7ec8Build\u524d\u53bb\u9009\u62e9\u6211\u4eec\u9700\u8981\u7684\u8fd9\u4e2a\u4ea7\u54c1Branch\u5206\u652f.<\/p>\n<p>Groovy\u6293\u53d6Git branch\u4ee3\u7801:<\/p>\n<pre class=\"prettyprint lang-bsh\">def gettags = (\"git ls-remote -h <a href=\"mailto:git@git.yanwenbo.cn\">git@git.yanwenbo.cn<\/a>:showerlee\/phpcms.git\").execute()\ngettags.text.readLines().collect { it.split()[1].replaceAll('refs\/heads\/', '')  }.unique()<\/pre>\n<p><a href=\"http:\/\/www.showerlee.com\/wp-content\/uploads\/2016\/03\/QQ20160311-11.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-1895\" src=\"http:\/\/www.showerlee.com\/wp-content\/uploads\/2016\/03\/QQ20160311-11-1024x425.png\" alt=\"QQ20160311-11\" width=\"1024\" height=\"425\" \/><\/a><\/p>\n<p>Choice Parameter\u4e5f\u662f\u7528\u6765\u7ed9\u6211\u4eecJob\u5b9a\u5236Build\u524d\u7684\u53ef\u9009\u53c2\u6570, \u4e0d\u8fc7\u8fd9\u91cc\u7684\u53c2\u6570\u53ef\u4ee5\u76f4\u63a5\u5199\u6b7b<\/p>\n<p>deploy_environment\u4e3a\u6211\u4eec\u7684\u53c2\u6570\u540d, \u5b9a\u4e49\u6211\u4eec\u7684\u90e8\u7f72\u73af\u5883\u540d,\u00a0prod, qa\u4e3a\u6211\u4eec\u5177\u4f53\u7684\u53ef\u9009\u9879, \u5b9a\u4e49\u6211\u4eec\u4ea7\u54c1\u7684\u4e24\u4e2a\u73af\u5883.<\/p>\n<p><a href=\"http:\/\/www.showerlee.com\/wp-content\/uploads\/2016\/03\/QQ20160311-8.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-1892\" src=\"http:\/\/www.showerlee.com\/wp-content\/uploads\/2016\/03\/QQ20160311-8-1024x427.png\" alt=\"QQ20160311-8\" width=\"1024\" height=\"427\" \/><\/a>2). \u6e90\u4ee3\u7801\u7ba1\u7406<\/p>\n<p>\u6211\u4eec\u53ef\u4ee5\u5229\u7528Jenkins\u5185\u7f6e\u7684Source Code Management\u5de5\u5177\u53bb\u6293\u53d6\u8fdc\u7a0bGit\u6216\u8005SVN\u4ed3\u5e93\u7684\u4ee3\u7801\u5230\u672c\u5730, \u8fd9\u91cc\u6211\u4eec\u6293\u53d6\u5b58\u653e\u5728\u6211\u4eecGitlab\u4e0a\u7684Playbook\u5230Jenkins\u7684workspace\u76ee\u5f55, \u7528\u6765\u8fdb\u884c\u540e\u7eed\u90e8\u7f72\u5de5\u4f5c, \u8fd9\u4e2a\u4ed3\u5e93\u5982\u9700\u8ba4\u8bc1,\u00a0\u6211\u4eec\u53ef\u4ee5\u5728Credentials add\u8fd9\u4e2a\u4ed3\u5e93\u7684\u7528\u6237\u8d26\u53f7\u5bc6\u7801, \u5176\u4f59\u5747\u4fdd\u6301\u9ed8\u8ba4\u5373\u53ef(\u9ed8\u8ba4Jenkins default\u4e0d\u652f\u6301Git, \u9700\u8981\u5230\u5176\u540e\u53f0\u5b89\u88c5Git\u63d2\u4ef6)<\/p>\n<p><a href=\"http:\/\/www.showerlee.com\/wp-content\/uploads\/2016\/03\/QQ20160311-9.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-1894\" src=\"http:\/\/www.showerlee.com\/wp-content\/uploads\/2016\/03\/QQ20160311-9-1024x557.png\" alt=\"QQ20160311-9\" width=\"1024\" height=\"557\" \/><\/a>3). Execute shell\u8fdb\u884c\u6700\u7ec8\u7684CLI\u90e8\u7f72.<\/p>\n<p>\u8fd9\u4e2aBuild\u6a21\u5757\u4e0b\u7684Execute shell\u65b9\u6cd5\u662fJenkins\u6bd4\u8f83\u5e38\u7528\u5e76\u975e\u5e38\u6838\u5fc3\u7684\u529f\u80fd, \u7528\u6765\u6267\u884c\u6211\u4eec\u90e8\u7f72\u8fc7\u7a0b\u4e2d\u6838\u5fc3\u7684\u547d\u4ee4.<\/p>\n<p>\u5f00\u5934\u548c\u7ed3\u5c3e\u7684set +x,\u00a0set\u00a0-x\u7528\u6765\u6253\u5f00\u548c\u5173\u95ed\u8be5\u90e8\u5206\u7684\u6269\u5c55\u53c2\u6570\u53ca\u547d\u4ee4<\/p>\n<p>\u5f00\u542fvirtualenv\u548c\u52a0\u8f7dansible\u73af\u5883\u53d8\u91cf<\/p>\n<pre class=\"prettyprint\"># source \/home\/deploy\/.virtualenv\/bin\/activate\n# . \/home\/deploy\/.virtualenv\/ansible\/hacking\/env-setup -q<\/pre>\n<p>\u8fdb\u5165\u8be5Job\u7684workspace\u76ee\u5f55\u4e0b\u4fdd\u5b58\u8be5playbook\u7684\u4ed3\u5e93\u5b50\u76ee\u5f55\u4e0b, \u68c0\u67e5ansible\u7248\u672c, \u5e76\u6267\u884c\u6700\u7ec8\u7684\u90e8\u7f72\u547d\u4ee4.<\/p>\n<pre class=\"prettyprint lang-bsh\">cd $WORKSPACE\/leon-playbook-phpcms1.1\nansible --version\nansible-playbook -i inventory\/$deploy_environment .\/deploy.yml -e project=phpcms -e branch=$branch_selector -e env=$deploy_environment<\/pre>\n<p>\u6ce8: -i\u00a0\u7528\u6765\u81ea\u5b9a\u4e49ansible host\u6587\u4ef6\u8def\u5f84, .\/deploy.yml\u4e3aansible-playbook\u5165\u53e3\u6587\u4ef6, -e \u540e\u53ef\u8ddf\u7ed9\u5f53\u524dsession\u6dfb\u52a0\u7684\u73af\u5883\u53d8\u91cf.<\/p>\n<p>\u8fd9\u91cc$deploy_environment $branch_selector \u4e3a\u8be5Job\u5b9a\u4e49\u597d\u7684\u53ef\u9009\u53c2\u6570, \u8be6\u89c13-1)<\/p>\n<p><a href=\"http:\/\/www.showerlee.com\/wp-content\/uploads\/2016\/03\/QQ20160311-10.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-1891\" src=\"http:\/\/www.showerlee.com\/wp-content\/uploads\/2016\/03\/QQ20160311-10-1024x266.png\" alt=\"QQ20160311-10\" width=\"1024\" height=\"266\" \/><\/a><\/p>\n<p>\u914d\u7f6e\u5b8c\u6bd5\u540e, save\u4fdd\u5b58.<\/p>\n<p>4. \u6267\u884cJob.<\/p>\n<p><a href=\"http:\/\/www.showerlee.com\/wp-content\/uploads\/2016\/03\/QQ20160311-12.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-large wp-image-1897\" src=\"http:\/\/www.showerlee.com\/wp-content\/uploads\/2016\/03\/QQ20160311-12-1024x336.png\" alt=\"QQ20160311-12\" width=\"1024\" height=\"336\" \/><\/a><\/p>\n<p>\u9009\u62e9master\u5206\u652f\u548cprod\u73af\u5883<\/p>\n<p><a href=\"http:\/\/www.showerlee.com\/wp-content\/uploads\/2016\/03\/QQ20160311-13.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1898\" src=\"http:\/\/www.showerlee.com\/wp-content\/uploads\/2016\/03\/QQ20160311-13.png\" alt=\"QQ20160311-13\" width=\"859\" height=\"302\" \/><\/a><\/p>\n<p>\u67e5\u770b\u8be5Job\u6700\u7ec8\u7684console output, \u4e5f\u5c31\u662f\u663e\u793a\u6211\u4eec\u5b9e\u9645\u5728CLI\u4e0b\u7684\u8f93\u51fa\u7ed3\u679c.<\/p>\n<p><a href=\"http:\/\/www.showerlee.com\/wp-content\/uploads\/2016\/03\/QQ20160311-14.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1899\" src=\"http:\/\/www.showerlee.com\/wp-content\/uploads\/2016\/03\/QQ20160311-14.png\" alt=\"QQ20160311-14\" width=\"347\" height=\"684\" \/><\/a><\/p>\n<h1 class=\"build-caption page-headline\">Console Output<\/h1>\n<pre class=\"prettyprint lang-bsh\">Started by user Leon Li\nBuilding in workspace \/home\/deploy\/jenkins\/workspace\/Phpcms-Dev\n &gt; git rev-parse --is-inside-work-tree # timeout=10\nFetching changes from the remote Git repository\n &gt; git config remote.origin.url <a href=\"mailto:git@git.yanwenbo.cn\">git@git.yanwenbo.cn<\/a>:showerlee\/Ansible-showerlee.git # timeout=10\nFetching upstream changes from <a href=\"mailto:git@git.yanwenbo.cn\">git@git.yanwenbo.cn<\/a>:showerlee\/Ansible-showerlee.git\n &gt; git --version # timeout=10\n &gt; git fetch --tags --progress <a href=\"mailto:git@git.yanwenbo.cn\">git@git.yanwenbo.cn<\/a>:showerlee\/Ansible-showerlee.git +refs\/heads\/*:refs\/remotes\/origin\/*\n &gt; git rev-parse refs\/remotes\/origin\/master^{commit} # timeout=10\n &gt; git rev-parse refs\/remotes\/origin\/origin\/master^{commit} # timeout=10\nChecking out Revision 6bf787dcad68219d8eee09cecb83cbca36edbef1 (refs\/remotes\/origin\/master)\n &gt; git config core.sparsecheckout # timeout=10\n &gt; git checkout -f 6bf787dcad68219d8eee09cecb83cbca36edbef1\n &gt; git rev-list 6bf787dcad68219d8eee09cecb83cbca36edbef1 # timeout=10\n[Phpcms-Dev] $ \/bin\/sh -xe \/tmp\/hudson7452069223867148990.sh\n+ set +x\nansible 2.1.0 (devel 6ddea3e915) last updated 2016\/02\/16 16:13:32 (GMT +800)\n  lib\/ansible\/modules\/core: (detached HEAD 8d126bd877) last updated 2016\/02\/16 16:19:09 (GMT +800)\n  lib\/ansible\/modules\/extras: (detached HEAD f6c5ed987f) last updated 2016\/02\/16 16:19:40 (GMT +800)\n  config file = \/home\/deploy\/jenkins\/workspace\/Phpcms-Dev\/leon-playbook-phpcms1.1\/ansible.cfg\n  configured module search path = \/home\/deploy\/active-ansible-modules\/\n\nPLAY ***************************************************************************\n\nTASK [setup] *******************************************************************\nok: [127.0.0.1]\n\nTASK [deploy : Backup current source code] *************************************\nchanged: [127.0.0.1]\n\ncmd: mv \/data\/deploy_dir\/phpcms \/data\/deploy_dir\/phpcms_master_1457681152\n\nstart: 2016-03-11 15:25:54.774716\n\nend: 2016-03-11 15:25:54.927415\n\ndelta: 0:00:00.152699\n\nTASK [deploy : Get new source code] ********************************************\nchanged: [127.0.0.1]\n\nTASK [deploy : Check if caches\/configs\/database.php exists] ********************\nok: [127.0.0.1]\n\nTASK [deploy : Check if test_dir exists] ***************************************\nok: [127.0.0.1]\n\nTASK [deploy : debug] **********************************************************\nok: [127.0.0.1] =&gt; {\n    \"msg\": \"\/data\/deploy_dir\/phpcms_master_1457681152\/caches\/configs\/database.php exists\"\n}\n\nmsg: \/data\/deploy_dir\/phpcms_master_1457681152\/caches\/configs\/database.php exists\n\nTASK [deploy : debug] **********************************************************\nok: [127.0.0.1] =&gt; {\n    \"msg\": \"\/data\/deploy_dir\/phpcms_master_1457681152\/test_dir exists\"\n}\n\nmsg: \/data\/deploy_dir\/phpcms_master_1457681152\/test_dir exists\n\nTASK [deploy : Copy remote necessary original config to new release when Product env] ***\nchanged: [127.0.0.1] =&gt; (item={u'name': u'db_config', u'dir': u'caches\/configs\/database.php'})\nchanged: [127.0.0.1] =&gt; (item={u'name': u'version_config', u'dir': u'caches\/configs\/version.php'})\n\nmsg: All items completed\n\nresults: [\n  {\n    \"src\": \"\/data\/deploy_dir\/phpcms_master_1457681152\/caches\/configs\/database.php\",\n    \"changed\": true,\n    \"group\": \"deploy\",\n    \"uid\": 606,\n    \"dest\": \"\/data\/deploy_dir\/phpcms\/caches\/configs\/database.php\",\n    \"checksum\": \"91869c2faa244f8c5de8a586636c6b4f3c0a2817\",\n    \"md5sum\": \"fd88a78a4629bca012a79d22fdcecadd\",\n    \"owner\": \"deploy\",\n    \"_ansible_no_log\": false,\n    \"item\": {\n      \"name\": \"db_config\",\n      \"dir\": \"caches\/configs\/database.php\"\n    },\n    \"state\": \"file\",\n    \"gid\": 608,\n    \"mode\": \"0644\",\n    \"invocation\": {\n      \"module_args\": {\n        \"src\": \"\/data\/deploy_dir\/phpcms_master_1457681152\/caches\/configs\/database.php\",\n        \"directory_mode\": null,\n        \"force\": true,\n        \"remote_src\": true,\n        \"dest\": \"\/data\/deploy_dir\/phpcms\/caches\/configs\/database.php\",\n        \"selevel\": null,\n        \"seuser\": null,\n        \"setype\": null,\n        \"group\": null,\n        \"content\": null,\n        \"serole\": null,\n        \"original_basename\": null,\n        \"delimiter\": null,\n        \"mode\": \"0644\",\n        \"regexp\": null,\n        \"owner\": null,\n        \"follow\": false,\n        \"validate\": null,\n        \"backup\": false\n      }\n    },\n    \"size\": 302\n  },\n  {\n    \"src\": \"\/data\/deploy_dir\/phpcms_master_1457681152\/caches\/configs\/version.php\",\n    \"changed\": true,\n    \"group\": \"deploy\",\n    \"uid\": 606,\n    \"dest\": \"\/data\/deploy_dir\/phpcms\/caches\/configs\/version.php\",\n    \"checksum\": \"d0eaedb46a36303eb3f3e2a77cc2a623062eff3c\",\n    \"md5sum\": \"7917d8199b7c6d5bc87ff3035a72670e\",\n    \"owner\": \"deploy\",\n    \"_ansible_no_log\": false,\n    \"item\": {\n      \"name\": \"version_config\",\n      \"dir\": \"caches\/configs\/version.php\"\n    },\n    \"state\": \"file\",\n    \"gid\": 608,\n    \"mode\": \"0644\",\n    \"invocation\": {\n      \"module_args\": {\n        \"src\": \"\/data\/deploy_dir\/phpcms_master_1457681152\/caches\/configs\/version.php\",\n        \"directory_mode\": null,\n        \"force\": true,\n        \"remote_src\": true,\n        \"dest\": \"\/data\/deploy_dir\/phpcms\/caches\/configs\/version.php\",\n        \"selevel\": null,\n        \"seuser\": null,\n        \"setype\": null,\n        \"group\": null,\n        \"content\": null,\n        \"serole\": null,\n        \"original_basename\": null,\n        \"delimiter\": null,\n        \"mode\": \"0644\",\n        \"regexp\": null,\n        \"owner\": null,\n        \"follow\": false,\n        \"validate\": null,\n        \"backup\": false\n      }\n    },\n    \"size\": 127\n  }\n]\n\nTASK [deploy : Copy dir test_dir to new release when Product env] **************\nchanged: [127.0.0.1]\n\ncmd: cp -a \/data\/deploy_dir\/phpcms_master_1457681152\/test_dir \/data\/deploy_dir\/phpcms\/\n\nstart: 2016-03-11 15:26:16.966237\n\nend: 2016-03-11 15:26:17.069705\n\ndelta: 0:00:00.103468\n\nTASK [deploy : Get php version] ************************************************\nchanged: [127.0.0.1 -&gt; localhost]\n\ncmd: python \/home\/deploy\/jenkins\/workspace\/Phpcms-Dev\/leon-playbook-phpcms1.1\/roles\/deploy\/files\/get_php_version.py <a href=\"http:\/\/www.showerlee.com\/\" rel=\"nofollow\">http:\/\/www.showerlee.com<\/a>\n\nstart: 2016-03-11 15:26:17.468311\n\nend: 2016-03-11 15:26:51.560313\n\ndelta: 0:00:34.092002\n\nstdout: PHP\/5.4.13\n\nTASK [deploy : debug] **********************************************************\nok: [127.0.0.1] =&gt; {\n    \"msg\": {\n        \"changed\": true,\n        \"cmd\": \"python \/home\/deploy\/jenkins\/workspace\/Phpcms-Dev\/leon-playbook-phpcms1.1\/roles\/deploy\/files\/get_php_version.py <a href=\"http:\/\/www.showerlee.com\/\" rel=\"nofollow\">http:\/\/www.showerlee.com<\/a>\",\n        \"delta\": \"0:00:34.092002\",\n        \"end\": \"2016-03-11 15:26:51.560313\",\n        \"rc\": 0,\n        \"start\": \"2016-03-11 15:26:17.468311\",\n        \"stderr\": \"\",\n        \"stdout\": \"PHP\/5.4.13\",\n        \"stdout_lines\": [\n            \"PHP\/5.4.13\"\n        ],\n        \"warnings\": []\n    }\n}\n\nmsg: {\n  \"changed\": true,\n  \"end\": \"2016-03-11 15:26:51.560313\",\n  \"stdout\": \"PHP\/5.4.13\",\n  \"cmd\": \"python \/home\/deploy\/jenkins\/workspace\/Phpcms-Dev\/leon-playbook-phpcms1.1\/roles\/deploy\/files\/get_php_version.py <a href=\"http:\/\/www.showerlee.com\/\" rel=\"nofollow\">http:\/\/www.showerlee.com<\/a>\",\n  \"start\": \"2016-03-11 15:26:17.468311\",\n  \"delta\": \"0:00:34.092002\",\n  \"stderr\": \"\",\n  \"rc\": 0,\n  \"stdout_lines\": [\n    \"PHP\/5.4.13\"\n  ],\n  \"warnings\": []\n}\n\nTASK [deploy : debug] **********************************************************\nok: [127.0.0.1] =&gt; {\n    \"msg\": \"PHP\/5.4.13\"\n}\n\nmsg: PHP\/5.4.13\n\nPLAY RECAP *********************************************************************\n127.0.0.1                  : ok=12   changed=5    unreachable=0    failed=0\n\nFinished: SUCCESS<\/pre>\n<p>\u8fd9\u6837\u6211\u4eec\u5c31\u5229\u7528Jenkins+Ansible+Gitlab, \u6210\u529f\u90e8\u7f72phpcms\u5230\u8fdc\u7a0bClient.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u6700\u8fd1\u4e00\u76f4\u5728\u5b66\u4e60Ansible\u7684\u4e00\u4e9bplaybook\u7684\u5199\u6cd5, \u6240\u4ee5\u4e00\u76f4\u6ca1\u6709\u600e\u4e48\u66f4\u65b0, \u60f3\u5230\u76ee\u524d\u5927\u5bb6\u5bf9\u8bf8\u5982saltstack, docker, Ansible\u7b49\u81ea\u52a8\u5316\u90e8\u7f72\u76f8\u5173\u7684\u5de5\u5177\u5f88\u611f\u5174\u8da3, \u4f46\u53c8\u82e6\u4e8e\u6ca1\u6709\u53ef\u5b66\u4e60\u7684\u4e2d\u6587\u5b9e\u4f8b, \u8fd9\u91cc\u6211\u5c31\u628a\u6211\u8fd9\u51e0\u4e2a\u6708\u6240\u63a5\u89e6\u5230\u76ee\u524d\u56fd\u5916\u6bd4\u8f83\u6d41\u884c\u7684\u90e8\u7f72\u7ecf\u9a8c\u7ed9\u5927\u5bb6\u5206\u4eab\u4e00\u4e0b. \u9996\u5148\u7ed9\u5927\u5bb6\u4ecb\u7ecd\u7684\u662fAnsible, \u6069, \u91cd\u8981\u7684\u95ee\u9898\u8bf4\u4e09\u904d, \u4e0d\u662fSaltstack, Ansible\u4f5c\u4e3a\u4e00\u4e2apython\u5199\u7684\u81ea\u52a8\u5316\u90e8\u7f72\u5de5\u5177, \u786e\u5b9e\u8f83\u4e4b\u524d\u6211\u6240\u63a5\u89e6\u7684Chef, saltstack, puppet\u66f4\u6709\u81ea\u5df1\u7684\u4e00\u4e9b\u4f18\u52bf, \u9996\u5148\u5c31\u662fagentless, \u65e0\u9700\u5728Linux client\u5b89\u88c5\u4efb\u4f55\u670d\u52a1\u5373\u53ef\u65e0\u7f1d\u8fde\u63a5Linux default ssh\u7aef\u53e3\u8fdb\u884c\u90e8\u7f72(windows\u9700\u8981\u5b89\u88c5winrm [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[1],"tags":[],"class_list":["post-93","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/blog.jsjs.org\/index.php?rest_route=\/wp\/v2\/posts\/93","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.jsjs.org\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.jsjs.org\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jsjs.org\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jsjs.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=93"}],"version-history":[{"count":0,"href":"https:\/\/blog.jsjs.org\/index.php?rest_route=\/wp\/v2\/posts\/93\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.jsjs.org\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=93"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jsjs.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=93"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jsjs.org\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=93"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}