首先是技术栈选择。 后端框架我选择了nodejs的koa框架,数据库使用了mysql(其实再加上一个redis也是同理)
搭建koa项目
确认了技术栈后我们先起个项目,起个koa的项目很简单,这里就不介绍流程了
项目搭建完后我们需要在项目根目录下写一个Dockerfile文件,用来构建koa项目的镜像。
# 制定node镜像的版本
FROM node:16.9.1
# 移动当前目录下面的文件到app目录下
ADD . /app/
# 进入到app目录下面,类似cd
WORKDIR /app
# 设置淘宝镜像 && 安装依赖 && build代码
RUN npm config set registry http://registry.npm.taobao.org && npm install && npm run build
# 对外暴露的端口,这里的3000需要和inde.js监听的端口一致
EXPOSE 3000
# 程序启动脚本,意思为 执行 npm start
CMD ["npm", "start"]
这一步完成后我们就可以在根目录下docker build . 打包这个koa项目镜像测试一下
- 首先我们docker images一下,看一下目前docker镜像都有哪些
- 然后在根目录下docker build .
- build完后我们可以再次docker images看一下
- 可以看到我们已经构建了一个没有命名没有版本的镜像
- 接下来我们可以给我们的镜像命名(方便后续docker命令,就可以不用每次复制镜像id号了), docker tag 镜像id 自定义名称:自定义版本号
- 可以看到这样我们就构建了一个名叫server 版本号为1的镜像
- 然后我们就可以run一下我们构建好的镜像测试一下
- docker run --name 自定义名称 -d(代表后台运行) -it(以交互模式运行容器并为容器重新分配一个伪输入终端) -p(将容器内的xxx端口映射至宿主机的xxx端口) 3000:3000 server:1(使用server镜像的1版本)
- 执行完后我们就可以在宿主机查看一下该端口号是否已经被占用,mac linux可以使用lsof(linux没有lsof的话可以装一个 yum/apt-get update 然后 yum/apt-get install lsof) lsof -i:3000
- 可以看到我们宿主机上的3000端口号已经被docker容器占用
- 现在我们可以进入容器内看一下项目文件是否被正确打包进去
- docker exec(docker exec的意思是在运行的容器中执行命令) -it(即使没有附加也保持STDIN 打开,分配一个伪终端) server(容器名称) /bin/bash(以/bin/bash的指令模式执行shell命令)
- 可以看到我们的项目确实被正确打包到了容器内的app目录下
测试到我们的dockerfile文件构建出来的镜像没有问题,接下来我们就可以使用docker-compose来同时启动我们的koa项目和mysql
在这一步前需要在koa项目中连接好数据库
host先设置为db或其他自定义的名字就可以,我这里是做了一个监测当前环境是否是容器的判断,如果我的koa项目没有在docker容器下运行则使用本地的mysql
设置好后我们在项目根目录下创建一个docker-compose.yml文件
version: "3"
services:
server:
build:
dockerfile: Dockerfile
context: .
image: server
volumes: # 这个磁盘挂载不用写,这是我项目中做图片上传后映射到服务器上用的
- ../img:/app/img
ports:
- "3000:3000"
links: # 重点为这里,我们把mysql重命名为db或者其他名字,就是我们koa项目里host里填写的名字
- mysql:db
depends_on: # 这里为设置server容器的依赖
- mysql
mysql:
image: mysql/mysql-server:latest
restart: always
environment:
MYSQL_ROOT_PASSWORD: "数据库root用户的密码"
MYSQL_USER: "要登录的数据库的账号,这里我们使用root登录就可以"
MYSQL_PASS: "root用户的密码"
expose: # 将本容器内的3306端口暴露
- "3306"
privileged: true
volumes: # 磁盘挂载
- ./db:/var/lib/mysql # 这里注意,在根目录目录下创建一个db空文件夹,每次docker-compose运行时,如果你需要重新初始化mysql的话需要把db文件夹目录下的文件都清空,否则mysql不会初始化
- ./init:/docker-entrypoint-initdb.d/ # mysql初始化时会执行这个文件夹下的init.sql
ports:
- "3307:3306" # 这里把3306映射到3307是因为,我把两个容器cicd到远程服务器后,我本地机器想连接远程服务器的话可以通过3307连接,就不需要把本地的数据库停掉了。否则每次连接远程服务器的数据库还需要把本地mysql停掉
command: [
'mysqld',
'--innodb-buffer-pool-size=80M',
'--character-set-server=utf8mb4',
'--collation-server=utf8mb4_unicode_ci',
'--default-time-zone=+8:00',
'--lower-case-table-names=1',
'--max_allowed_packet=100M',
'--default-authentication-plugin=mysql_native_password'
]
可能有同学会比较好奇,为什么我们设置了一个expose暴露3306端口,又设置一个ports暴露端口,有什么区别吗。 这里我们简单讲一下两者的区别
-
prots
ports
暴露容器端口到主机的任意端口或指定端口,用法:-
ports: - "80:80" # 绑定容器的80端口到主机的80端口 - "9000:80" # 绑定容器的80端口到主机的9000端口 - "443" # 绑定容器的443端口到主机的任意端口,容器启动时随机分配绑定的主机端口号
- 不管是否指定主机端口,使用
ports
都会将端口暴露给主机和其他容器。
-
expose
expose
暴露容器给link
到当前容器的容器,或者暴露给同一个networks
的容器,用法:-
expose: - "3000" - "8000"
- 以上指令将当前容器的端口
3000
和8000
暴露给其他容器。 - 和
ports
的区别是,expose
不会将端口暴露给主机,主机无法访问expose
的端口。
init.sql
use mysql;
update user set host = '%' where user = 'root';
select host, user from user;
CREATE DATABASE `koa` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; # 创建要用的库
flush privileges;
use koa;
CREATE TABLE `user_info` ( # 创建表 内容按自己需要的写
`id` int NOT NULL AUTO_INCREMENT,
`create_time` timestamp NOT NULL,
`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`username` varchar(255) NOT NULL,
`password` varchar(255) NOT NULL,
`nickname` varchar(255) DEFAULT NULL,
`sex` varchar(255) DEFAULT NULL,
`signature` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb3;
# 插入一条数据,可以不写
INSERT INTO `user_info` (`id`, `create_time`, `update_time`, `username`, `password`, `nickname`, `sex`, `signature`) VALUES (10, '2022-01-14 21:32:37', '2022-01-14 21:32:58', '123', '123', NULL, NULL, NULL);
然后我们就可以测试一下了
- 在根目录下运行 docker-compose pull 先下载容器依赖的镜像
- 然后docker-compose up --force-recreate -d
- 耐心等待,完成后我们可以docker ps查看一下在运行中的docker容器
- 之后我们就可以用insomnia(或者其他api测试工具如postman)测试一下我们的koa项目是否能正常使用
接下来我们就可以准备用jenkins来做CI/CD了!