分类目录归档:网络技术

使用Docker部署Stirling PDF(二)

1.源码修改
基于《使用Docker部署Stirling PDF》这篇文章展开说,主要是针对Stirling这个项目进行定制,在前述的文章中代码中

services:
  stirling-pdf:
    image: frooodle/s-pdf:0.32.0
    ports:
      - '8080:8080'
    volumes:
      - ./StirlingPDF/trainingData:/usr/share/tessdata # Required for extra OCR languages
      - ./StirlingPDF/extraConfigs:/configs
      - ./StirlingPDF/customFiles:/customFiles/
      - ./StirlingPDF/logs:/logs/
      - ./StirlingPDF/pipeline:/pipeline/
    environment:
      - DOCKER_ENABLE_SECURITY=false
      - LANGS=en_GB

通过volumes的形式,来提供宿主机和容器内文件进行映射,extraConfigs中需要修改custom_settings.yml内容,这个文件内容会覆盖settings.yml内容。目前主要修改的方式是复制settings.yml到custom_settings.yml中,对特定内容进行修改。下面显示的都是需要修改的部分,其余的内容都保留就行了。

system:
  customHTMLFiles: true # enable to have files placed in /customFiles/templates override the existing template HTML files

ui:
  appName: 'Full PDF' # application's visible name
  homeDescription: '' # short description or tagline shown on the homepage
  appNameNavbar: 'Full PDF' # name displayed on the navigation bar

endpoints:
  toRemove: ['pipeline','view-pdf','replace-and-invert-color-pdf','split-pdf-by-chapters', 'ocr-pdf'] # list endpoints to disable (e.g. ['img-to-pdf', 'remove-pages'])
  groupsToRemove: ['pipeline','view-pdf', 'replace-and-invert-color-pdf','split-pdf-by-chapters', 'ocr-pdf'] # list groups to disable (e.g. ['LibreOffice'])

customFiles文件夹中新建static和templates两个文件夹,其中static中添加的都是照片,templates文件夹中添加fragments文件夹和home.html文件,文件目录需要和github中的源码进行对应。源码目录

这个是本地已经修改的文件夹,里面包括修改的源码和照片fullpdf

2.项目部署
本地部署和线上部署有区别,本地部署docker restart 镜像id, 线上部署的需要重新pull,docker-compose up(ubuntu)。

3.todo
目前图片处理是使用付费的chatgpt在处理,需要寻找免费的图片处理工具;在暗黑的情况下,网站的logo显示有问题,这个需要解决。

使用Docker部署Stirling PDF

0.注意问题:docker pull中网络会出现问题,需要设置下载地址

#/etc/docker/daemon.json
{
    "registry-mirrors": [
    "https://docker.1panelproxy.com",
    "https://2a6bf1988cb6428c877f723ec7530dbc.mirror.swr.myhuaweicloud.com",
    "https://docker.m.daocloud.io",
    "https://hub-mirror.c.163.com",
    "https://mirror.baidubce.com",
    "https://your_preferred_mirror",
    "https://dockerhub.icu",
    "https://docker.registry.cyou",
    "https://docker-cf.registry.cyou",
    "https://dockercf.jsdelivr.fyi",
    "https://docker.jsdelivr.fyi",
    "https://dockertest.jsdelivr.fyi",
    "https://mirror.aliyuncs.com",
    "https://dockerproxy.com",
    "https://mirror.baidubce.com",
    "https://docker.m.daocloud.io",
    "https://docker.nju.edu.cn",
    "https://docker.mirrors.sjtug.sjtu.edu.cn",
    "https://docker.mirrors.ustc.edu.cn",
    "https://mirror.iscas.ac.cn",
    "https://docker.rainbond.cc"
    ]
}

1.dockerfile文件

services:
  stirling-pdf:
    image: frooodle/s-pdf:0.32.0
    ports:
      - '8080:8080'
    volumes:
      - ./StirlingPDF/trainingData:/usr/share/tessdata # Required for extra OCR languages
      - ./StirlingPDF/extraConfigs:/configs
      - ./StirlingPDF/customFiles:/customFiles/
      - ./StirlingPDF/logs:/logs/
      - ./StirlingPDF/pipeline:/pipeline/
    environment:
      - DOCKER_ENABLE_SECURITY=false
      - LANGS=en_GB

2.启动和访问

docker-compose up
http:://ip:8080

3.域名中进行设置
4.设置反向代理和ssl

1.如果没有安装宝塔,那么使用npm nginx proxy manager
2.因为安装了宝塔,端口443和80端口,所以可以使用宝塔设置反向代理和ssl

Docker介绍和基本使用

docker

1.为什么使用docker

docker使用的是container技术,比如部署rails过程中,最起码是需要服务器和数据库,其中服务器一般用nginx,数据库一般使用mysql,可以nginx使用一个独立容器,而mysql使用一个独立容器,这两个容器相互独立,又可以联通,容器本身是跨平台的,在部署的时候非常方便。

2.相关术语

镜像 image,是一个模板,容器是从镜像中生成的。

容器 container,应用运行在容器中。

仓库 repository:打包好的镜像是放置在仓库中的。

3.安装docker

1.需要提供镜像服务

需要提供镜像加速服务,这个在阿里云的[镜像加速器]这个服务模块中,用户有自己的加速链接(下面的registry-mirrors中的就是阿里云提供的)。这对mac的加速链接的方式是在docker客户端的Settings docker engine中进行修改。

{
  "builder": {
    "gc": {
      "defaultKeepStorage": "20GB",
      "enabled": true
    }
  },
  "experimental": false,
  "registry-mirrors": [
    "https://xx"
  ]
}

示例:

#拉取镜像
docker pull nginx  #也可以是docker pull nginx:latest 最后这个是标签

#列出所有镜像 
docker images  #也可以是docker image ls

#启动容器
docker run -d --name web -p 8080:80 nginx:latest
#启动容器命令 docker run 
#-d 在后台运行
#--name web  定义容器名称为web
# -p 8080:80 定义端口,其中宿主机(就是本地的mac)端口为8080,容器端口为80
#nginx:latest 容器所需要的镜像名称

docker ps #查看启动的容器
docker ps -a #查看所有容器

#进入容器
docker exec -it web /bin/bash  #进入容器中,使用bash命令
apt update #更新源,如果没有更新源,那么vim安装不成功
apt install vim -y  #安装vim工具,更新/usr/share/nginx/html/index.html文件

#访问这个容器项目
访问链接http://localhost:8080/,修改主页内容/usr/share/nginx/html,修改html文件

#使用容器生成镜像
docker commit web hello-world  #web是目前容器的名称,hello-world是生成镜像的名称

#给镜像打tag,也可以理解是生成一份不同名字的拷贝
docker tag hello-world zhengjiajun/hello-world:latest
docker tag hello-world zhengjiajun/one

#将镜像提交到hub中需要将镜像的名称定义为user/name的形式,这也是上面tag的原因
#我的hub用户名称是zhengjiajun,所以将镜像命名为zhengjiajun/name的形式
#登录docker hub需要进行登录  登录和退出的命令分别是
docker login
docker logout

#docker上传到hub中
docker push zhengjiajun/one

使用docker-compose.yml文件

#启动 默认是docker-compose.yml文件,也可以使用自定义名称web.yml
docker-compose -f web.yml up -d

#文件结构,包括四个一级的key
version services  networks volumes

version ,对应关系https://www.cnblogs.com/fengfengyang/p/16442146.html

version: 3

services

#services的关键字
image #从官方或者自己的hub中获取镜像
build #从Dockerfile中构建镜像
ports #端口映射(容器内的端口映射到宿主机端口) “8080:80” 左边是宿主机的端口,右边的容器端口
volumes #卷挂载,“dbdata:/var/lib/mysql” 左边是要映射的目录,右边是容器目录
environment #设置环境变量,供容器内应用使用
  environment:
    MYSQL_ROOT_PASSWORD:admin
depends_on :依赖关系,确保服务的前后启动顺序 
command : 容器启动后执行的命令
networks : 网络设置
restart:always  随宿主机启动

networks

#常见驱动类型
bridge(默认模式) overlay host
#格式
drive:host

volumes

1.外部卷,docker外部创建和管理,可以被容器使用,示例是external:true
2.命名卷,有固定名称,在宿主机预定义的目录下面
volumes:
  dbdata:
3.匿名卷
4.主机卷,宿主机的文件系统挂载到容器中
/path/in/host:/path/in/container

完整的docker-compose.yml文件

version: '3.8'
services:
  db:
    container_name: sqldb
    image: mariadb
    volumes:
      - dbdata:/var/lib/mysql
    restart: always
    environment:
      - MYSQL_ROOT_PASSWORD: admin
      - MYSQL_DATABASE: jayzen_db
      - MYSQL_USER: my_user
      - MYSQL_PASSWORD: my_password
    networks:
      - mynet
  phpmyadmin:
    image: phpmyadmin
    restart: always
    ports:
      - 8080:80
    environment:
      -PMA_ARBITRARY: 1
    networks:
      - mynet
networks:
  mynet:
volumes:
  dbdata:

使用Dockerfile文件

#保存为文件Dockerfile
FROM ubuntu:latest
MAINTAINER jayzen <jayzen@foxmail.com>
RUN apt update #对镜像执行的命令
CMD ["echo", "hello world"] #镜像构建完成之后对容器执行的命令

#创建镜像, docker build创建镜像命令,-t name, 镜像名称, .当前文件夹下面
docker build -t myubuntu:1.0 .

#运行镜像,输出hello world表示成功运行 
docker run b8df944a8864 #b8df944a8864是镜像的id

ActiveSupport::Concern的作用和实现原理

作用:解决了rails中module之间的混入问题,参考如下代码示例

#代码示例
module SecondLevelModule 
  def self.included(base); base.extend ClassMethods; end
  def second_level_instance_method; 'ok'; end

  module ClassMethods
    def second_level_class_method; 'ok'; end
  end 
end

module FirstLevelModule 
  def self.included(base); base.extend ClassMethods; end
  def first_level_instance_method; 'ok'; end

  module ClassMethods
    def first_level_class_method; 'ok'; end
  end
  include SecondLevelModule
end

class BaseClass
  include FirstLevelModule
end

上面的代码中,示例方法调用没有问题,FirstLevelModule中的类方法调用也没有问题,SecondLevelModule中的类方法不能被调用,这就是module的混入问题。

p BaseClass.new.first_level_instance_method #ok
p BaseClass.new.second_level_instance_method #ok
p BaseClass.first_level_class_method #ok
p BaseClass.second_level_class_method #error

Rails2中的解决方式

#只是修改included中方法
module FirstLevelModule 
  def self.included(base)
    base.extend ClassMethods
    base.send :include, SecondLevelModule
  end
end
ActiveSupport::Concern的使用
require 'active_support'
module SecondLevelModule
  extend ActiveSupport::Concern #add

  def second_level_instance_method; 'ok'; end

  module ClassMethods
    def second_level_class_method; 'ok'; end
  end
end

module FirstLevelModule
  extend ActiveSupport::Concern #add

  def first_level_instance_method; 'ok'; end

  module ClassMethods
    def first_level_class_method; 'ok'; end
  end
  include SecondLevelModule
end

class BaseClass
  include FirstLevelModule
end

append_features的作用原理:是include的hook方法

#先于included方法执行,included方法默认是空的,append_features会检查模块是否包含在祖先链中,如果没有,添加进去
module M
  def self.append_features(base)
    return false
  end
end

class Demo
  include M
end

#改了append_features方法,是它不在祖先链中
p Demo.ancestors #[Demo, Object, PP::ObjectMixin, Kernel, BasicObject]

#如果要改写的同时要添加到祖先链中,需要在append_features中添加super方法
module M
  def self.append_features(base)
    super
  end
end
#查看self和base
module M
  def self.append_features(base)
    p "self is #{self}"
    p "base is #{base}"
  end
end

class Demo
  include M
end
#"self is M"
#"base is Demo"

ActiveSupport::Concern的源代码

module ActiveSupport  
  module Concern
    class MultipleIncludedBlocks < StandardError #:nodoc:
      def initialize
        super "Cannot define multiple 'included' blocks for a Concern"
      end
    end

    def self.extended(base) #:nodoc:
      base.instance_variable_set(:@_dependencies, [])
    end

    def append_features(base)
      if base.instance_variable_defined?(:@_dependencies)
        base.instance_variable_get(:@_dependencies) << self
        return false
      else
        return false if base < self
        @_dependencies.each { |dep| base.include(dep) }
        super
        base.extend const_get(:ClassMethods) if const_defined?(:ClassMethods)
        base.class_eval(&@_included_block) if instance_variable_defined?(:@_included_block)
      end
    end

    def included(base = nil, &block)
      if base.nil?
        raise MultipleIncludedBlocks if instance_variable_defined?(:@_included_block)

        @_included_block = block
      else
        super
      end
    end

    def class_methods(&class_methods_module_definition)
      mod = const_defined?(:ClassMethods, false) ?
        const_get(:ClassMethods) :
        const_set(:ClassMethods, Module.new)

      mod.module_eval(&class_methods_module_definition)
    end
  end
end

单单只是extend ActiveSupport::Concern

#only extend ActiveSupport::Concern
module SecondLevelModule
  extend ActiveSupport::Concern #add

  def second_level_instance_method; 'ok'; end

  module ClassMethods
    def second_level_class_method; 'ok'; end
  end
end

#只执行下面 的代码,其中base是SecondLevelModule,这个模块设置实例变量
def self.extended(base) #:nodoc:
  base.instance_variable_set(:@_dependencies, [])
end

#result, SecondLevelModule中包含实例变量@_dependencies,变量值为[]
<#SecondLevelModule, @_dependencies: []>

extend ActiveSupport::Concern的同时include SecondLevelModule

#extend ActiveSupport::Concern and include SecondLevelModule
module FirstLevelModule
  extend ActiveSupport::Concern #add

  def first_level_instance_method; 'ok'; end

  module ClassMethods
    def first_level_class_method; 'ok'; end
  end
  include SecondLevelModule
end

#执行下面的代码
def self.extended(base) 
  base.instance_variable_set(:@_dependencies, [])
end #result,FirstLevelModule中添加实例变量@_dependencies,将其设值为[]

def append_features(base) #这里的base还是FirstLevelModule
  if base.instance_variable_defined?(:@_dependencies)
    base.instance_variable_get(:@_dependencies) << self #这里是self是SecondLevelModule
    return false
  else
    return false if base < self
    @_dependencies.each { |dep| base.include(dep) }
    super
    base.extend const_get(:ClassMethods) if const_defined?(:ClassMethods)
    base.class_eval(&@_included_block) if instance_variable_defined?(:@_included_block)
  end
end

#result
1.FirstLevelModule中设置实例变量,而且这个实例变量包含SecondLevelModule
<#FirstLevelModule, @_dependencies: [SecondLevelModule]>
2.return false表示不把SecondLevelModule添加到ancestors中

只是include FirstLevelModule

#only inclue no active_support::concern
class BaseClass
  include FirstLevelModule
end

#只执行下面
def append_features(base) #这里的base是BaseClass
  if base.instance_variable_defined?(:@_dependencies)
    base.instance_variable_get(:@_dependencies) << self #这里是self是SecondLevelModule
    return false
  else
    #base < self是用来判断FirstLevelModule是否在BaseClass的祖先链中
    return false if base < self #这里的self是FirstLevelModule
    #@_dependencies是self即FirstLevelModule的实例变量
    @_dependencies.each { |dep| base.include(dep) } 
    super #调用super方法,实现默认的append_features方法
    base.extend const_get(:ClassMethods) if const_defined?(:ClassMethods)
    base.class_eval(&@_included_block) if instance_variable_defined?(:@_included_block)
  end
end

总结:一般在插件中使用ActiveSupport::Concern,使用规则一般如下:

module SecondLevelModule
  extend ActiveSupport::Concern #需要extend

  included do #这里放实例方法
    def second_level_instance_method; 'ok'; end
  end

  module ClassMethods #这里面放类方法
    def second_level_class_method; 'ok'; end
  end
end

class Demo
  #进行include使用
  include SecondLevelModule
end

使用宝塔快速搭建wordpress

1.购买服务器

2.服务器中安装宝塔

#ubuntu 命令
wget -O install_panel.sh https://download.bt.cn/install/install_panel.sh && sudo bash install_panel.sh ed8484bec

3.安装成功之后,命令行显示如下的内容

外网面板地址: http://ip:8888/c62d6af5
内网面板地址: http://ip:8888/c62d6af5
username: name
password: password

#备注8888端口默认是没有开的,需要自己添加开通

4.面板设置

[面板设置]中修改面板账号和面板密码
[面板设置]中重新设置安全入口
[面板设置]修改端口,需要在ECS中添加安全组的地址

5.安装的软件

nginx 1.20
mysql 5.6
phpmyadmin 4.9
php 7.3
pure-ftpd

6.创建站点

[网站]中[添加站点],添加ftp和数据库的账号和密码
通过ecs后台域名添加域名解析
点击站点,添加wordpress为伪静态

7.上传wordpress

1./www/wwwroot/xiangtec.com文件夹下面放wordpress内容,删除原来的404和index文件
输入数据库的名称和密码
2.使用上文提到的域名解析对应的域名进行访问

8.缓存设置

安装主题2012
宝塔在php中[安装扩展],安装opcache和memcached
wordpress中插件安装 memcached is you friend 并且启动

9.插件安装

WP Githuber MD   #一个使用marddown的文本编辑器

10.外观-主题文件编辑器

修改footer  [外观]-[主题编辑器]-修改printf函数内容

11.优化设置

日志分割 [计划任务]
数据库备份  可以从[计划任务]中进行备份,也可以从[数据库]中进行备份
ssl  [网站]-[ssl]-[let's Encrypt]
恶意解析,通过ip进行访问   [网站]-[默认站点]-选择站点
php版本切换 [网站]-[网站名]-[PHP版本]