部署 koa 服务
一、应用介绍
1. 基础构成
centerOS+docker+koa+vue
2. 实施步骤:
- 安装 docker
- 安装配置 node 镜像
- 构建镜像
- 运行项目
- 测试部署是否成功
二、实施
1.安装配置 docker
- 介绍
Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。
Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。
容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。
- Docker 是世界领先的软件容器平台。
- Docker 使用 Google 公司推出的 Go 语言 进行开发实现,基于 Linux 内核 的cgroup,namespace,以及 AUFS 类的 UnionFS 等技术,对进程进行封装隔离,属于操作系统层面的虚拟化技术。 由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器。Docker 最初实现是基于 LXC。
- Docker 能够自动执行重复性任务,例如搭建和配置开发环境,从而解放了开发人员以便他们专注在真正重要的事情上,构建杰出的软件。
- 用户可以方便地创建和使用容器,把自己的应用放入容器。容器还可以进行版本管理、复制、分享、修改,就像管理普通的代码一样。
解决的问题:“明明在我这台机器上都可以运行,为什么跑你那去就出错了?”
方法:打包我们的应用以及依赖到 Docker 容器中,从而避免了环境不一致
最终目的:为了线下线上环境一致,更方便的部署
Docker 带来了什么(优点)
- 环境隔离(‘隔离,安全’):Docker 实现了资源隔离,一台机器运行多个容器互无影响。
- 更高效的资源利用(节约成本):Docker 容器的运行不需要额外的虚拟化管理程序的支持,它是内核级的虚拟化,可以实现更高的性能,同时对资源的额外需求很低。
- 更快速的交付部署(敏捷):使用 Docker,开发人员可以利用镜像快速构建一套标准的研发环境,开发完成后,测试和运维人员可以直接通过使用相同的环境来部署代码。
- 更易迁移扩展(可移植性):Docker 容器几乎可以在任意的平台上运行,包括虚拟机、公有云、私有云、个人电脑、服务器等,这种兼容性让用户可以在不同平台之间轻松的迁移应用。
- 更简单的更新管理(高效):使用 Dockerfile,只需要很少的配置修改,就可以替代以往大量的更新工作。并且所有修改都是以增量的方式进行分发和更新,从而实现自动化和高效的容器管理。
-
概念
镜像(Image):Docker 镜像(Image),就相当于是⼀个 root ⽂件系统。⽐如官⽅镜像 ubuntu:16.04 就包含了完整的⼀套
Ubuntu16.04 最⼩系统的 root ⽂件系统。
容器(Container):镜像(Image)和容器(Container)的关系,就像是⾯向对象程序设计中的类和实例⼀样,镜像是静态的定义,
容器是镜像运⾏时的实体。容器可以被创建、启动、停⽌、删除、暂停等。
仓库(Repository):仓库可看着⼀个代码控制中⼼,⽤来保存镜像 -
官方 centOS 安装docker教程
或者:
curl -fsSL https://get.docker.com -o get-docker.sh
DRY_RUN=1 sh ./get-docker.sh
- 设置镜像源第一
yum-config-manager --add-repo http://mirrors.aliyun.com/cloer-re/linux/centos/docker-re.repo
- 设置镜像源第二
mkdir -p /etc/docker
编辑/etc/docker/daemon.json文件,并输入国内镜像源地址
vi /etc/docker/daemon.json
Docker中国官方镜像加速
{
"registry-mirrors": ["https://registry.docker-cn.com"]
}
- 附录:国内镜像 *
- Docker中国官方镜像加速
–registry-mirror=https://registry.docker-cn.com
- 网易163镜像加速
–registry-mirror=http://hub-mirror.c.163.com
- 中科大镜像加速
–registry-mirror=https://docker.mirrors.ustc.edu.cn
- 阿里云镜像加速
–registry-mirror=https://{your_id}.mirror.aliyuncs.com
- daocloud镜像加速
–registry-mirror=http://{your_id}.m.daocloud.io
也可以直接下载站点镜像:
docker pull hub.c.163.com/library/tomcat:latest # 复制站点链接用 pull 下来
阿里云跟daocloud镜像加速需要注册账号
2. docker 镜像使用
拉取 node
docker pull node # lasted 版本
查看 node 镜像
docker images
创建 Dockerfile 文件
切换到项目根目录下
创建Dockerfile
文件
npm 设置
# syntax=docker/dockerfile:1
# 第一行是语法分析器指令,指定docker解析文件时用什么语法,会在开始构建之前升级解析器兼容旧版本。
# 指向版本1语法的最新版本。BuildKit 会在生成之前自动检查语法的更新,确保使用的是最新版本。
# 继承容器,可以继承多个
FROM node
# 指定制作我们的镜像的联系人信息(镜像创建者)
MAINTAINER HJJ
# 创建容器内的项目存放目录
RUN mkdir -p /home/koa-serve
# 先拷贝依赖文件安装依赖,这样可以提高效率
COPY ['package.json', './']
# cd到koa-serve文件夹下
WORKDIR /home/koa-serve
# 安装项目依赖包
# 公司内网taobao被墙,官网反而ok,这个得注意
RUN npm set registry http://registry.npm.taobao.org/ \
# 查看请求的进度
&& npm config set loglevel=http \
&& npm install pm2 -g \
# 等于--production,现在推荐使用这个--omit=dev参数设置
&& npm install --omit=dev
# 将根目录下的文件都copy到container(运行此镜像的容器)文件系统的koa-serve文件夹下
ADD . /home/koa-serve/
# 配置环境变量
ENV HOST 0.0.0.0
ENV PORT 10000
# 容器对外暴露的端口号
EXPOSE 80
# 容器启动时执行的命令,类似npm run start
CMD ["npm", "run", "serve-dev"]
yarn 设置
# syntax=docker/dockerfile:1
FROM node
# 指定制作我们的镜像的联系人信息(镜像创建者)
MAINTAINER HJJ
# 创建容器内的项目存放目录
RUN mkdir -p /home/koa-serve
# 先拷贝依赖文件安装依赖,这样可以提高效率
COPY ['package.json', './']
# cd到koa-serve文件夹下
WORKDIR /home/koa-serve
# 将根目录下的文件都copy到container(运行此镜像的容器)文件系统的koa-serve文件夹下
ADD . /home/koa-serve/
# 安装项目依赖包
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
&& apk update \
&& apk add yarn \
&& yarn config set registry https://registry.npm.taobao.org/ \
&& yarn add pm2 -g \
&& yarn \
# 这一窜命令,设置镜像源到国内(加速),更新,安装yarn,yarn设置国内镜像源,yarn安装node依赖
# 配置环境变量
ENV HOST 0.0.0.0
ENV PORT 10000
# 容器对外暴露的端口号
EXPOSE 80
# 容器启动时执行的命令,类似npm run start
CMD ["yarn", "serve-dev"]
node-demo例子
# syntax=docker/dockerfile:1
FROM node
RUN apk add --no-cache python2 g++ make
WORKDIR /app
COPY . .
RUN yarn install --omit=dev
CMD ["node", "src/index.js"]
EXPOSE 3000
创建 .dockerignore 文件
切换到项目根目录下
创建.dockerignore
文件
.DS_Store
npm-debug.log*
log
node_modules
/package-lock.json
/yarn-lock.json
*.tar
*.md
# Editor directories and files
.vscode
.history
上传项目到服务器/git 拉取 gitlab 仓库项目
本地使用7-zip压缩项目为tar类型,或者直接是zip文件
yum -y install lrzsz # 安装
#上传文件到服务器
rz -bye
#服务端解压tar
tar -xvf xxx.tar
#服务端解压zip
unzip -xvf xxx.zip
#删除压缩包
rm -rf ****.tar
rm -rf ****.zip
根目录下构建镜像
docker build -t koa-serve .
检查构建是否成功
查看是否有该 image
docker ps -a
查看该容器是否在运行
docker ps
注意查看其中的STATUS状态是否为Up,端口号是否正确。
运行容器
docker run -dp 80:10000 --name “koa-container” koa-serve # 顺便不对会导致容器没有启动失败
-d 表示容器会在后台运行
–name 是我们给容器起的名字,这个名字是唯一的
-p 表示端口映射,80:10000前面为主机端口,后面是容器端口
如果端口有问题,停掉应用,然后不给容器起名称(名称随机),即执行下面的命令来操作。
docker run --rm --net=host -v /data/logs/koa-serve/test1:/home/koa-serve/log -e “PORT=8003” --name “koa-serve-1” -dp 20020:8003 koa-serve
测试
curl -i localhost:端口号
返回index.html页面的信息即成功
设置开机自启动
docker run --restart=always
如果已经启动了则可以使用如下命令:
docker update --restart=always <容器ID>
导出容器为镜像
docker commit my_container my_image # 提交容器为镜像
docker images #查看是否成功
docker save my_image:my_tag | gzip > my_image.tar.gz # 导出镜像并压缩成gz文件
部署
docker load < my_image.tar.gz # 导入镜像包
docker run -it --restart=always --name jdh-node-serve -dp 20001:4000 jdh-node-serve:v1.0.0.ns1 # 启动容器
发布镜像
登录docker hub,并注册
docker login
docker tag 标签名 用户名/标签名
docker tag docker_demo robin365/docker_demo
docker push 用户名/标签名
docker push robin365/docker_demo
上传成功则可以使用docker pull
命令下载下来
多个容器管理
使用 docker-compose
配置 docker-compose.yml
version: "3"
services:
web:
image: node:12-alpine
working_dir: /code
volumes:
- .:/code
ports:
- "3000:3000"
command: npm start
mysql:
image: mysql:5.6
volumes:
- ./data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=123456
- MYSQL_DATABASE=koa_docker
ports:
- "3306:3306"
nginx:
image: nginx:1.17
volumes:
- ./static:/code/static
- ./conf/default.conf:/etc/nginx/conf.d/default.conf
ports:
- "80:80"
一次启动多个服务
docker-compose up
附录2:docker 常用命令
#查看当前docker版本
docker -v
#查看当前本地所有镜像
docker images
#构造镜像,用法docker build -t 镜像名称 .
docker build -t docker_demo .
#用于容器与主机之间的数据拷贝。用法docker cp 主机文件地址 容器内地址。12d7f14v45cv为容器id。
docker cp /www/runoob 12d7f14v45cv:/www/
#创建一个新的容器并运行,-d为后台执行,-p 9000:3000前面为主机端口,后面是容器端口。docker_demo镜像名
docker run -dp 9000:3000 docker_demo
#启动已被停止的容器
docker start docker_demo
#关闭已被启动的容器
docker stop docker_demo
#重新启动容器
docker restart docker_demo
#杀掉一个运行中的容器。
docker kill -s KILL docker_demo
#删除一个或多少容器。-f :通过SIGKILL信号强制删除一个运行中的容器-l :移除容器间的网络连接,而非容器本身-v :-v 删除与容器关联的卷
docker rm -f docker_demo、docker_demo1
#在运行的容器中执行命令。104e28f2f072容器id
sudo docker exec -it 104e28f2f072 /bin/bash
#列出容器。 -a:所有容器包含没有运行的
docker ps
#获取容器获取容器的日志 104e28f2f072容器id,-t:显示时间戳
docker logs -f -t 104e28f2f072
#登陆镜像仓库
docker login
#获取镜像
docker pull
#上传镜像
docker push
#查看指定镜像的创建历史。
docker history docker_demo
#重启服务
systemctl restart docker
#查看资源状态
docker stats
#镜像常用命令
docker pull [镜像名称:版本] 拉取镜像
docker images 镜像列表
docker rmi [镜像名称:版本] 删除镜像
docker history [镜像名称] 镜像操作记录
docker tag [镜像名称:版本][新镜像名称:新版本]
docker inspect [镜像名称:版本] 查看镜像详细
docker search [关键字] 搜索镜像
docker login 镜像登陆
#容器常用命令
docker ps -a 容器列表(所有容器)
docker ps 查看所有(运行的)容器
docker exec -ti <id> bash 以 bash 命令进入容器内
docker run -ti --name [容器名称][镜像名称:版本] bash 启动容器并进入
docker logs 查看容器日志
docker top <container_id> 查看容器最近的一个进程
docker run -ti --name [容器名称] -p 8080:80 [镜像名称:版本] bash 端口映射
docker rm <container_id> 删除容器
docker stop <container_id> 停止容器
docker start <container_id> 开启容器
docker restart <container_id> 重启容器
docker inspect <container_id> 查看容器详情
docker commit [容器名称] my_image:v1.0 容器提交为新的镜像
Docker 清理命令
# 杀死所有正在运行的容器
docker kill $(docker ps -a -q)
# 删除所有已经停止的容器
docker rm $(docker ps -a -q)
# 删除所有未打 dangling 标签的镜像
docker rmi $(docker images -q -f dangling=true)
# 通过镜像的id来删除指定镜像
docker rmi <image id>
# 删除所有镜像
docker rmi $(docker images -q)
为这些命令创建别名
# ~/.bash_aliases
# 杀死所有正在运行的容器.
alias dockerkill='docker kill $(docker ps -a -q)'
# 删除所有已经停止的容器.
alias dockercleanc='docker rm $(docker ps -a -q)'
# 删除所有未打标签的镜像.
alias dockercleani='docker rmi $(docker images -q -f dangling=true)'
# 删除所有已经停止的容器和未打标签的镜像.
alias dockerclean='dockercleanc || true && dockercleani'
# 清理命令
docker system prune
docker volume prune
docker network prune
docker container prune
docker image prune
# 容器瘦身
ID=$(docker run -d image-name /bin/bash)docker export $ID | docker import – flat-image-name
docker命令解释
docker run -ti
# -t 让docker分配一个伪终端并绑定到容器的标准输入上
# -i 则让容器的标准输入保持打开.
# Docker中系统镜像的缺省命令是 bash,如果不加 -ti bash 命令执行了自动会退出。这是因为如果没有衔接输入流,本身就会马上结束。加-ti 后docker命令会为容器分配一个伪终端,并接管其stdin/stdout支持交互操作,这时候bash命令不会自动退出
docker run -rm
# -rm 容器将在退出时自动删除
docker run -d -p
# -d 后台运行
# -p 端口映射 外部:内部
# 导入镜像包
docker load -i xxx.tar
docker load < my_image.tar.gz
# 导出镜像包
docker export -i xxx.tar
# 保存镜像
docker save my_image:my_tag | gzip > my_image.tar.gz
# 导入 / 导出容器
# 从文件中导入容器镜像:
cat my_container.tar.gz | docker import - my_image:my_tag
# 导出既有容器:
docker export my_container | gzip > my_container.tar.gz
# 暴露端口(Exposing ports)
# 通过宿主容器暴露输入端口相当 繁琐但有效的。
# 例如使用 -p 将容器端口映射到宿主端口上(只使用本地主机 (localhost) 接口):
docker run -p 127.0.0.1:$HOSTPORT:$CONTAINERPORT --name CONTAINER -t someimage
# 在 Dockerfile 中定义用户并以该用户运行,避免在容器中以 ROOT 身份操作:
RUN groupadd -r user && useradd -r -g user userUSER user
# 参考:https://baijiahao.baidu.com/s?id=1720802321830094075&wfr=spider&for=pc
# 将容器保存为镜像
docker commit my_container my_image
docker images #查看是否成功
docker save my_image:my_tag | gzip > my_image.tar.gz
nvidia-docker run --rm --net=host -v /data/logs/ocr/idcard:/recognize_document/log -d 镜像名:gpu -p 10051 -I -G 0 -L 127.0.0.1
nvidia-docker run --rm --net=host -v /data/logs/ocr/idcard:/recognize_document/log -d recognize_id_card_9264:gpu -p 10051 -I -G 0 -L 127.0.0.1
# 文件映射
# -v /data/logs/ocr/idcard:/recognize_document/log
#-e的作用是指定容器内的环境变量。
# 其他
--net=host
-I
-G 0
-L
附录3:linux命令
1. 上传文件命令
yum -y install lrzsz # 安装
rz -bye # 使用,弹窗选择文件
-+, --append:将文件内容追加到已存在的同名文件
-a,--ascii:以文本方式传输
-b, --binary:以二进制方式传输,推荐使用
--delay-startup N:等待N秒
-e, --escape:对所有控制字符转义,建议使用
-E, --rename:已存在同名文件则重命名新上传的文件,以点和数字作为后缀
-p, --protect:对ZMODEM协议有效,如果目标文件已存在则跳过
-q, --quiet:安静执行,不输出提示信息
-v, --verbose:输出传输过程中的提示信息
-y, --overwrite:存在同名文件则替换
-X, --xmodem:使用XMODEM协议
--ymodem:使用YMODEM协议
-Z, --zmodem:使用ZMODEM协议
--version:显示版本信息
--h, --help:显示帮助信息
2.下载多个文件
sz file1 file2 file3
解压zip
unzip xxx.zip
解压tar
tar -vxf xxx.tar
建立软连接
ln -s /usr/local/lib/node_modules/bin/xx /usr/local/bin/xx
一般QA
-
Job for docker.service failed because the control process exited with error
配置镜像试试 -
端口问题
docker port 容器id,找不到映射
docker run -itd -v /root/docker/store/mongo/data:/data/db -p 27017:27017 -e MONGO_INITDB_ROOT_USERNAME="root" -e MONGO_INITDB_ROOT_PASSWORD="ken123456" --name mongo5 mongo:5.0.5
-e MONGO_INITDB_ROOT_USERNAME="root" -e MONGO_INITDB_ROOT_PASSWORD="roothjj"
docker run -itd -p 27017:27017 --name mongo5 mongo:5.0.5
- curl: (7) Failed connect to localhost:8000; 拒绝连接
端口映射设置有问题,查看index.js
,Dockerfile
,运行的命令比如:
docker run -dp 4000:8000 koa-demo # 端口1是外部访问的:端口2内部应用启动的
-
npm中间错误问题
在安装puppeteer过程中遇到一些错误,记录一下
首先可能遇到node install.js错误,可以使用一下命令参数安装puppeteer
npm i --save puppeteer --ignore-scripts
或者先执行一下命令再安装puppeteer
npm config set unsafe-perm true
npm i puppeteer
其次可能会遇到各种库没有安装的错误,比如libX11-xcb.so.1,具体所需依赖可以查看Troubleshooting.或直接执行一下命令
sudo apt install gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget
还有sandbox 问题,可以尝试在无沙箱模式下运行puppeteer
const browser = await puppeteer.launch({args: ['--no-sandbox', '--disable-setuid-sandbox']});
-
npm fund 问题。
-
puppeteer linux问题解决方案
https://blog.csdn.net/weixin_39995439/article/details/110553818
DebianQA
查看版本号
cat /etc/debian_version
结果
11.3
uname 命令可以显示电脑以及操作系统的相关信息,输入下面的命令:
uname -a
ldd 查看软件依赖
puppeteerQA
https://storage.googleapis.com/chromium-browser-snapshots/linux_x64/%d/chrome-linux.zip
Puppeter安装的捆绑Chromium缺少必要的共享库依赖项。
要修复此问题,您需要在Dockerfile中安装缺失的依赖项和最新的Chromium包:
替换debian的源为阿里的源,然后安装chromium的依赖包。
deb http://mirrors.aliyun.com/debian/ bullseye main non-free contrib
deb-src http://mirrors.aliyun.com/debian/ bullseye main non-free contrib
deb http://mirrors.aliyun.com/debian-security/ bullseye-security main
deb-src http://mirrors.aliyun.com/debian-security/ bullseye-security main
deb http://mirrors.aliyun.com/debian/ bullseye-updates main non-free contrib
deb-src http://mirrors.aliyun.com/debian/ bullseye-updates main non-free contrib
deb http://mirrors.aliyun.com/debian/ bullseye-backports main non-free contrib
deb-src http://mirrors.aliyun.com/debian/ bullseye-backports main non-free contrib
apt-get update \
&& apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf libxss1 \
--no-install-recommends \
sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \
# 更改镜像源(可用)
dep http://ftp.de.debian.org/debian bullseye main contrib non-free
https://pkgs.org/download/google-chrome-unstable
dep http://extras.getpagespeed.com/debian bullseye main contrib non-free
https://centos.pkgs.org/8/getpagespeed-x86_64/google-chrome-unstable-81.0.4021.2-1.x86_64.rpm.html
deb/de-src区别
deb行是相对于二进制软件包的,您可以使用进行安装apt。
deb-src相对于源代码包(由下载apt-get source $package),然后进行编译。
仅当您要自己编译某些软件包或检查源代码中是否有错误时,才需要源软件包。普通用户不需要包含此类存储库。
因此,如果我只通过Synaptic或apt-get install安装软件包,则只需要第一行,deb…而不是deb-src…?
QA:
target packages is configured multiple times in
源配置配多了
参考
- docker文件里面的项目部署操作步骤: https://docs.docker.com/get-started/
- 开发NodeJS步骤例子:https://github.com/docker/labs/tree/master/developer-tools/nodejs/porting