Docker|Docker X SystemD折腾向(用Docker手动安装Ghost博客的奇妙经历)

前言 本来之前一直在平台上记录心得,但好友给我看了自己搭的Ghost博客,着实漂亮,恰逢计网附加作业是搭建一个个人网站,就有了趁这次机会搭一个博客并把部分文章迁移过去的想法
选择Ghost,一是因为自己之前搭建/维护的网页基本都是php,后来又接触了python的网络编程,想试试新东西——Ghost博客是基于node.js的框架,正好如我所愿;二是因为真的挺漂亮。
而选择Docker搭建的原因则比较现实了:我的学生服务器上还维护着几个其他项目,担心乱搞会搞崩原本的环境。虽然Ghost官方提供了现成的镜像可以一键部署,但是抱着学习的心态,还是选择了自己开一个ubuntu16.04的容器手动搭建。官方文档其实已经有非常详细的步骤,但是自己作死踩了不少坑,故作此记录
准备 下面是官方文档中提出的要求事实上看到第五项我就应该反应过来预想中的搭建方式肯定会出问题

  • Ubuntu 16.04 or Ubuntu 18.04
  • NGINX (minimum of 1.9.5 for SSL)
  • A supported version of Node.js
  • MySQL 5.5, 5.6, or 5.7 (not >= 8.0)
  • Systemd
  • A server with at least 1GB memory
  • A registered domain name
环境搭建
  • 容器启动 为了日后维护方便用-p选项开了三个端口,其中2368是Ghost默认的端口。这里其实没有必要对此进行映射,映射后搭建完成后还是得开个反向代理监听2368,否则博客里许多地方都是默认跳转到localhost:2368的orz
    -it则是启动交互模式, -v设置共享文件夹
    docker run -it -v /docker:/docker -p 8168:2368 -p 8122:22 -p 8100:80 --privileged=true --name=m_ghost daocloud.io/library/ubuntu:latest /bin/bash

  • 初步环境配置 由于容器是轻量化的虚拟技术,原本的设计意图是一个容器只运行一个应用,我们将其作为轻量虚拟机使用时需要手动安装很多ubuntu发行版已经自带的功能
    apt-get update apt-get upgrade apt-get install sudo apt-get install vim apt-get install openssh-server #安装ssh

    其中要提一下ssh,安装好后需要sudo vim /etc/sshd_config打开配置文件,并将PermitRootLogin一项前的注释去掉,把后面的参数改为yes,再service sshd start启动服务
  • 创建新用户 Ghost博客出于安全考虑,不允许使用root用户安装,故此步是必需的
    adduser eva #eva是我设置的用户名,可在命名规则内随意更换 usermod -aG sudo eva #添加到sudo用户组 su eva #切换至该用户,后面步骤全部使用该用户进行

  • 安装nginx
    sudo apt-get install nginx

  • 安装mysql
    sudo apt-get install mysql-server

  • 安装Node.js 此处需要注意安装对应版本的node.js,Ghost支持的版本一般会比最新版本晚一代,可以在官网查询
    curl -sL 'https://deb.nodesource.com/setup_10.x' | sudo -E bash #去掉引号再使用 sudo apt-get install -y nodejs

安装Ghost 在新版本中我们得以使用官方安装工具Ghost-CLI来进行安装,免去了自己下载包、自己改配置文件的繁琐步骤当然也有会卡住的Bug
  • 安装Ghost-CLI
    sudo npm install ghost-cli@latest -g

    之后可以使用ghost help来获得帮助,并可以在flags and options查询更多选项与指令以个性化安装
  • 创建Ghost安装目录 注意现在你不是root用户,在/root或/home下安装极有可能出错
    sudo mkdir -p /var/www/ghost #-p选项是为了确保有这个文件夹,没有则创建 sudo chown eva:eva /var/www/ghost #改变文件夹所属用户与用户组 sudo chmod 775 /var/www/ghost cd ghost #下一步操作也在ghost文件夹下进行

  • 安装Ghost
    ghost install

    这里有可能会卡在 Downloading and installing Ghost 这里,如果是卡在 Downloading 或者 Fetching packages,那就是服务器网不好,等待它自己重试即可;如果卡在 Building fresh packages 长达二十分钟多,那就是安装卡住了,需要按Ctrl+C退出安装,然后执行
    ghost uninstall cd.. sudo rm -rf ghost

    然后从创建文件夹那一步重新开始按流程做
    如果安装正常进行的话,就会让你自定义一些信息。
    Enter your blog URL: (http://localhost:2368) Enter your MySQL hostname: (localhost) Enter your MySQL username: Enter your MySQL password: Enter your Ghost database name: Do you wish to set up "ghost" mysql user? Do you wish to set up Nginx? Do you wish to set up SSL? Set up Systemd?

    到这里都是按官网文档安装即可,基本上懒得设置的话一路默认下去,如果是正常安装的话到这里基本就没啥事了,安装完后登录url就能看到页面了,阿里云服务器的话别忘了到控制台安全组开放端口就行
    但是标题都是折腾向了怎么可能平安无事呢(笑
踩坑:Systemd 在刚刚的Set up Systemd?那一步时,我按照官网的推荐选了yes,然后就喜闻乐见的报错退出了

Docker|Docker X SystemD折腾向(用Docker手动安装Ghost博客的奇妙经历)
文章图片
image.png
结合之前的项目经历,一股不详的预感油然而生
  • Systemd是什么?
    Systemd是一个系统管理守护进程、工具和库的集合,用于取代System V初始进程。Systemd的功能是用于集中管理和配置类UNIX系统。
    Systemd 的核心是一个叫单元unit的概念,它是一些存有关于服务service(在运行在后台的程序)、设备、挂载点、和操作系统其他方面信息的配置文件。Systemd 的其中一个目标就是简化这些事物之间的相互作用,因此如果你有程序需要在某个挂载点被创建或某个设备被接入后开始运行,Systemd 可以让这一切正常运作起来变得相当容易。(在没有 Systemd 的日子里,要使用脚本来把这些事情调配好,那可是相当丑陋的。)
    简单来说就是一个启动系统的时候用于管理各种服务的进程。在还没有systemd的时候,内核会去运行/sbin/init,随后这个程序会在名为 SysVinit 的系统中运行其余的各种启动脚本。现在Systemd则取而代之成为了第一个执行的进程,理所当然的,她的PID为1
  • 为什么会报错:容器与虚拟机的区别 如上所述,我们来查看一下当前容器内的第一个进程是什么
    sudo ps -p 1

    然后发现PID为1的进程是/bin/bash!为什么会这样呢?
    要搞清楚原因,先得重新回顾一下Docker的设计意图与特点
    Docker最早是使用一种被称为LXC的容器技术,后来改用runC,另一方面,Docker的最大特色之一是被称为AuFS的分层文件系统。每一个镜像都会先创建一个只读的文件层,而每一个基于其的容器则不断往上添加新的文件层,每层存储的是其与镜像所不同的地方。
    该特性使得容器非常的轻量,甚至允许上千个基于同一镜像的容器共享区区1Gb的空间,这是传统VM不可能做到的。
    Docker没有传统意义上的内核,其虚拟化并不像传统虚拟机一样使用数套不同的硬件驱动、初始化进程、加载模块等,更很少像虚拟机一样各自拥有一整套系统资源,而是通过“命名空间”的技术隔离进程。一般地,容器和宿主系统共用同一套内核。因此,容器在轻量化的同时,也导致了其隔离性的缺乏
    比起一个虚拟机,Docker的概念其实更接近于一般讲的进程沙箱,例如OJ里常用来防止提交的代码危害系统安全的那种。虽然用起来和轻量化的虚拟机无异,但是和虚拟机还是有着巨大的不同,其设计意图也不是想在每一个容器内跑一个完整的系统,而是在每一个容器内跑一个单独的进程/应用,使得其在批量化测试、快速部署/迁移等场合有着亮眼的表现。像我过去一样把docker当成虚拟机一样使用、在每个容器里部署一套笨重的LNMP无疑是越俎代庖的行为
    这也解释了为什么会报错:我启动的容器并没有、也不需要systemd这种用来在启动时管理加载过程的进程,在她眼里,自己的存在只是为了运行run命令时输入的/bin/bash而已。
    关于这块更多的知识,可以参考StackOverflow的这个回答
    • 如何解决 1.在本不存在SystemD的系统里模拟一个能执行systemctl的脚本 有一个优秀的项目叫docker-systemctl-replacement,通过重写/bin/systemctl使得进程能在没有systemd的情况下使用systemctl启动和停止服务
      具体用法举例如下
    wget https://raw.githubusercontent.com/gdraheim/docker-systemctl-replacement/master/files/docker/systemctl.py -O /usr/local/bin/systemctl

    然而我们并不是需要systemctl命令来管理服务,而是Ghost框架需要依赖SystemD本身,所以根本没用
    2.在启动容器时将/sbin/int作为启动命令,并使用privileged=true来赋予其访问宿主系统内核的权限 例如
    docker run -d -v /docker:/docker -p 8168:2368 -p 8122:22 -p 8100:80 --privileged=true --name=m_ghost daocloud.io/library/ubuntu:latest /sbin/init

    然而依旧报错,镜像里根本就没有/sbin/init......
    但是没有关西!我在这之前把自己配好的环境commit成了一个镜像,那个镜像是可以成功启动的,而且pid1也是/sbin/init
    但是那个容器里面的mysql坏掉了....出现了如下报错
    Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)

    而且网上对此的解决方案都毫无用处....
    3.使用官方镜像 老实说这样根本就没有解决问题嘛....有时间去研究下它的Dockerfile好了
    顺带一提直接用其Dockerfile来build镜像会出问题,意义不明
At Last 最后我还是使用了官方镜像....
具体操作如下
docker pull ghost docker run -d -v /docker:/docker -p 8168:2368 -p 8122:22 -p 8100:80 --name=m_ghost ghost # 注意最后不用跟任何命令

【Docker|Docker X SystemD折腾向(用Docker手动安装Ghost博客的奇妙经历)】唔然后就搭起来啦...接下来的事情就只有进入我的博客主页然后按说明慢慢配置各项主题、设计等等了
暂时没有域名so配置代理、配置SSL证书啥的都先搁置了,有需要的可以参考这里
结果最后也没有解决systemd和mysql的问题....是时候好好读一读操作系统原理了XD

    推荐阅读