最近使用nextjs
网站开发,希望使用docker
进行生产环境的部署,减少环境的依赖可重复部署操作。我采用的是Dockerfile
编写应用镜像方式+ docker-compose
实现容器部署的功能。
Docker
Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。我们可以通过将开发代码打包到docker 镜像中,上传到docker hub中,待发布时通过拉取docker hub镜像启动docker 容器,实现代码运行环境的高度一致,并提高部署效率。
安装
docker 提供了各种不同系统的安装方式,,因为我们常用的正式部署环境使用linux的缘故,我这里只介绍linux里如何安装docker以及如何配置docker国内镜像加速。
1、脚本安装
$ curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun
2、手动命令安装
# 先卸载旧版本的docker安装包,后安装新版
$ sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
$ sudo yum install -y yum-utils \
device-mapper-persistent-data \
lvm2
镜像加速
docker在国内网络环境使用会出现镜像下载过慢,甚至无法下载的问题,这里提供几个配置国内加速镜像源头地址, 在/etc/docker/daemon.json文件中写入如下内容:
{
"registry-mirrors": [
"https://<your-mirror-id>.mirror.aliyuncs.com", // 阿里云的加速地址,每个人都不一样
"https://docker.mirrors.sjtug.sjtu.edu.cn", // 上海交大
"https://docker.nju.edu.cn", // 南京大学
"https://docker.m.daocloud.io",// DaoCloud
"https://mirror.baidubce.com", // 百度云
"https://dockerproxy.com"// DockerProxy 代理
]
}
配置的时候需要将后面的备注信息删除,配置后需要重启docker服务:
sudo systemctl restart docker
重启完成后可以通过拉取一个docker镜像来验证镜像源是否可用,如:
$ docker pull node:18
常用命令
docker中又几个命令是需要我们记住的,因为需要经常使用到,如下简单介绍下几个常见的docker命令:
$ docker pull nginx:latest # 从镜像仓库拉取nginx:latest镜像
$ docker search nginx # 搜索镜像库的nginx相关镜像
$ docker push nginx:0.0.1 # 提交本地镜像nginx:0.0.1到当前登录的镜像仓库
$ docker ps -a # 列出当前主机中所有的docker容器
$ docker run -it nginx /bin/bash # 基于nginx镜像启动一个docker容器
$ docker pause containername # 暂停docker 容器
$ docker start containername # 启动docker容器
$ docker stop containername # 停止docker容器
$ docker restart containername # 重启docker容器
$ docker attach -it containername /bin/bash # 进入docker 容器,此种方式进入退出后会使得docker容器停止
$ docker exec -it containername /bin/bash # 进入docker 容器,此种方式进入退出后不会使得docker容器停止
$ docker export containername > containername.tar # 导出docker容器快照
$ docker rm containername # 删除docker 容器
$ docker logs -f containername # 持续输出docker容器的日志信息
$ docker cp containerID:container_path host_path # 复制主机文件到对应docker容器的地址
Dockerfile
Docker
可以通过从Dockerfile
中读取指令来自动构建图像。Dockerfile
是一个文本文档,其中包含用户可以在命令行上调用以组装图像的所有命令。本文介绍了可以在Dockerfile
中使用的命令。
编写DockerFile
1、在项目根目录创建Dockerfile文件
构建应用镜像的基础是创建对应的dockerfile文件,常规的我们会选择将dockerfile文件创建在项目的根目录,当然也可以自定义指定位置,只要在之后的构建过程指定路径就可以了
2、dockerfile编写依赖
我这里为了减少容器的大小,所以dockerfile使用了多阶段构建的方式实现,首先是依赖阶段实现依赖库的下载,具体如下:
FROM node:18-alpine AS deps
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
RUN apk update
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn config set registry https://registry.npm.taobao.org
RUN yarn install --frozen-lockfile
需要注意:
nodejs
对应版本,查看package.json
中的版本要求
"engines": {
"node": ">=18.17.0"
}
- 我这里将软件源修改为国内镜像,默认的国外镜像可能导致软件无法更新下载
- 更新前端库镜像为淘宝镜像
3、构建阶段
由于已经完成依赖的下载,构建阶段只需要进行编译打包即可:
FROM node:18-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN yarn config set registry https://registry.npm.taobao.org
RUN yarn build && yarn install --production
4、运行阶段
完成构建后,就需要我们配置容器的基础配置,如环境变量、工作目录、监听端口、应用启动命令等:
FROM node:18-alpine AS runner
WORKDIR /app
ENV NEXT_TELEMETRY_DISABLED 1
ENV NODE_ENV production
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
RUN yarn config set registry https://registry.npm.taobao.org
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
USER nextjs
EXPOSE 3000
ENV PORT 3000
CMD ["node_modules/.bin/next", "start"]
Docker-Compose
新的 Compose V2
支持将 compose
命令作为 Docker CLI
的一部分,现已推出。Compose V2
将 compose
功能集成到 Docker
平台中,继续支持之前的大部分 docker-compose
功能和标志。您可以通过使用 docker compose
而不是 docker-compose
将连字符 (-) 替换为空格来运行 Compose V2
。
Compose是Docker官方提供一个负责实现Docker 容器集群的快速编排,实现定义和运行多个Docker容器的应用。通过编写docker-compose文件可对多个服务同时进行启动/停止/更新(可定义依赖,按顺序启动服务)。
相关概念
- 项目(project):一个docker-compose.yml 组成一个project
- 服务(service):定义容器,配置需要运行的容器实例。一个project中由多个service组成,每个service定义了容器运行的镜像
命令
我们可以通过docker compose来查看帮助命令。
[root@VM_0_16_centos ~]# docker compose --help
Usage: docker [OPTIONS] COMMAND
A self-sufficient runtime for containers
Options:
--config string Location of client config files (default "/root/.docker")
-c, --context string Name of the context to use to connect to the daemon (overrides DOCKER_HOST env var and default context set with "docker context use")
-D, --debug Enable debug mode
-H, --host list Daemon socket(s) to connect to
-l, --log-level string Set the logging level ("debug"|"info"|"warn"|"error"|"fatal") (default "info")
--tls Use TLS; implied by --tlsverify
--tlscacert string Trust certs signed only by this CA (default "/root/.docker/ca.pem")
--tlscert string Path to TLS certificate file (default "/root/.docker/cert.pem")
--tlskey string Path to TLS key file (default "/root/.docker/key.pem")
--tlsverify Use TLS and verify the remote
-v, --version Print version information and quit
Management Commands:
builder Manage builds
config Manage Docker configs
container Manage containers
context Manage contexts
engine Manage the docker engine
image Manage images
network Manage networks
node Manage Swarm nodes
plugin Manage plugins
secret Manage Docker secrets
service Manage services
stack Manage Docker stacks
swarm Manage Swarm
system Manage Docker
trust Manage trust on Docker images
volume Manage volumes
Commands:
attach Attach local standard input, output, and error streams to a running container
build Build an image from a Dockerfile
commit Create a new image from a container's changes
cp Copy files/folders between a container and the local filesystem
create Create a new container
diff Inspect changes to files or directories on a container's filesystem
events Get real time events from the server
exec Run a command in a running container
export Export a container's filesystem as a tar archive
history Show the history of an image
images List images
import Import the contents from a tarball to create a filesystem image
info Display system-wide information
inspect Return low-level information on Docker objects
kill Kill one or more running containers
load Load an image from a tar archive or STDIN
login Log in to a Docker registry
logout Log out from a Docker registry
logs Fetch the logs of a container
pause Pause all processes within one or more containers
port List port mappings or a specific mapping for the container
ps List containers
pull Pull an image or a repository from a registry
push Push an image or a repository to a registry
rename Rename a container
restart Restart one or more containers
rm Remove one or more containers
rmi Remove one or more images
run Run a command in a new container
save Save one or more images to a tar archive (streamed to STDOUT by default)
search Search the Docker Hub for images
start Start one or more stopped containers
stats Display a live stream of container(s) resource usage statistics
stop Stop one or more running containers
tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
top Display the running processes of a container
unpause Unpause all processes within one or more containers
update Update configuration of one or more containers
version Show the Docker version information
wait Block until one or more containers stop, then print their exit codes
Run 'docker COMMAND --help' for more information on a command.
常用命令
$docker-compose up #启动docker-compose.yml中的所有容器,命令退出时,所有容器都将停止
$docker-compose up -d #启动docker-compose.yml中的所有容器,在后台启动容器并使它们保持运行
$docker-compose logs -f #查看该容器的日志打印
$docker logs -f contianer_id #查看某一个容器的启动日志打印
$docker-compose stop #停止compose服务
$docker-compose restart #重启compose服务
$docker-compose rm #删除compose服务
$docker-compose ps #查看compose 服务
$docker-compose kill #杀死compose服务
编写docker-compse.yml文件
完成dockerfile
文件编写后,我们就需要通过编写docker-compose.yml
配置文件来启动容器了。我这里是使用nginx
来部署,配置如下:
version: "3.1"
services:
db:
image: mysql:8
command:
--default-authentication-plugin=mysql_native_password
--sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
--group_concat_max_len=102400
restart: unless-stopped
volumes:
- ./data/mysql/:/var/lib/mysql/
environment:
TZ: Asia/Shanghai # 指定时区
MYSQL_ROOT_PASSWORD: "nextjs" # 配置root用户密码
MYSQL_DATABASE: "nextjs" # 业务库名
MYSQL_USER: "nextjs" # 业务库用户名
MYSQL_PASSWORD: "nextjs" # 业务库密码
ports:
- 3306:3306
nextjs:
build: .
ports:
- "3000:3000"
environment:
TZ: Asia/Shanghai # 指定时区
container_name: nextjs
volumes:
- ./:/app/
depends_on:
- db
restart: unless-stopped
nginx:
image: nginx:mainline-alpine
container_name: nginxserver
restart: unless-stopped
ports:
- "80:80"
volumes:
- ./.next:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
networks:
nodeapp-network:
driver: bridge
Nginx配置
如上可以看出,我一共创建了三个容器,一个数据容器db
,一个nextjs
容器是我们的应用还有一个nginx
容器是web
服务,nginx
里还需要将我们的配置文件映射到容器内,nginx-conf
内容如下:
server {
listen 80;
listen [::]:80;
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
server_name patientplatypus.com www.patientplatypus.com localhost;
# location /back {
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_set_header Host $http_host;
# proxy_set_header X-NginX-Proxy true;
# proxy_http_version 1.1;
# proxy_set_header Upgrade $http_upgrade;
# proxy_set_header Connection "upgrade";
# proxy_pass http://nodejs:8000;
# }
location / {
proxy_pass http://nextjs:3000;
}
location ~ /.well-known/acme-challenge {
allow all;
root /var/www/html;
}
}
启动容器
通过如下的学习,只需要我们的宿主机器安装了docker-compse即可直接使用如下命令:
$docker-compose up -d