什么是Docker?
Docker是一种虚拟容器技术,本质上是运行在宿主机上的进程(共享内核),它通过命名空间(Namespaces)实现了资源隔离,并通过CGroups(Control Groups)实现了资源的限额,同时通过写时复制(copy-on-write)实现了高效的文件操作。
Namespaces隔离:文件系统、网络、进程间通信、主机名、进程号、用户权限
CGroups限额:CPU、内存、磁盘 I/O 和带宽
copy-on-write:多个容器之间共享一份镜像
一、docker安装
1、安装
安装前先查看docker是否已安装,以及linux内核是否满足要求
# 查看docker
$ docker -v
# 查看内核,内核版本要>3.10
$ uname -r
1.)快速安装
通过下面的快捷命令安装
$ curl -sSL https://get.docker.com/ | sh
2.)手动安装
也可以通过依赖包手动安装(以centos为例)
# 更新yum包
$ sudo yum update
# 安装依赖包
$ sudo yum install -y yum-utils device-mapper-persistent-data lvm2
# 设置国内docker镜像源
$ sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# 查看仓库中所有docker,安装
$ yum list docker-ce --showduplicates | sort -r
$ sudo yum install docker-ce
2、卸载docker
# Ubuntu|Debian
$ sudo apt-get remove docker-ce docker-ce-cli
# centOS
$ sudo yum remove docker docker-common docker-selinux docker-engine container-selinux
卸载Docker默认会保留原Docker的镜像、网络、存储卷等,如需全新安装Docker,需删除目录/var/lib/docker
3、docker服务
# 启动/关闭服务
$ sudo systemctl start docker
$ sudo systemctl stop docker
# 加入随机启动
$ sudo systemctl enable docker
二、docker常用命令
查看docker系统配置信息
$ sudo docker info
1.)sudo权限设置
若每次使用docker命令都需要sudo,比较麻烦,可以通过以下命令添加当前用户到docker附属组:
$ sudo usermod -aG docker 当前用户名 # 需要注销后登录生效
2.)查看容器/镜像
$ docker ps # 查看本地容器
$ docker images # 查看本地镜像
# 查看容器详情
$ docker inspect xxx
# 查看容器top进程
$ docker top xxx
3.)下载镜像
创建容器前,可先下好远程镜像,也可以在创建时再下载
# 先查找远程镜像
$ docker search xxx
# 下载
$ docker pull xxx
4.)新建容器
最少参数的创建
# -d:表示后台运行,-it:表示以交互的方式创建,可视化时可通过console打开
$ docker run -d -it --name 容器名 --restart always 镜像名
更多参数:映射端口、dns、持久存储卷、初始化进程防容器退出
# -p:映射端口,--dns:指定dns解析服务器(/etc/resolv.conf),-v:映射路径(可重复多个),/bin/sh:保持一个进程运行,否则容器会退出
$ docker run -dit -p 宿主端口:容器端口 --dns=8.8.8.8 --name 容器名 -v 宿主路径:容器路径 --restart always 镜像:标签 /bin/sh
docker中安装centos无法使用systemctl命令管理进程,报以下错误:
Failed to get D-Bus connection: Operation not permitted
原因:需要特权才能启动systemd进程,解决方案:
docker run -dit --privileged 其它参数 init
5.)启动/停止容器
$ docker start | restart xxx # 启动/重启
$ docker stop xxx # 停止容器
$ docker kill xxx # 强行终止,关闭进程
6.)进入容器
# /bin/sh或/bin/bash可简写sh或bash
$ docker exec -it xxx /bin/sh
# 自动执行脚本
$ docker exec -it xxx sh -c "chmod +x ./app/entry.sh && ./app/entry.sh"
7.)删除容器/镜像
# 删除容器前需先停止
$ docker stop xxx
$ docker rm xxx
# 强制删除
$ docker rm xxx -f
# 删除镜像
$ docker rmi xxx # -f 强制删除
8.)容器/镜像改名
# 容器改名
$ docker rename 原容器名 新容器名
# 镜像改名
$ docker tag 原镜像 新镜像 # 会生成一个新名,镜像id一样
$ docker rmi 原镜像
三、构建镜像
1、手动构建镜像
用基础镜像创建一个容器,手动安装好一切,然后用容器生成镜像:
$ docker commit 容器名 新镜像名
2、自动构建镜像:Dockerfile
1.)Dockerfile配置
新建Dockerfile并配置相关内容,下面以配置一个基于alpine的pm2安装并运行node应用为例:
# 基础镜像源
FROM alpine
# 创建者信息
MAINTAINER hoby
# 修复时区
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo 'Asia/Shanghai' > /etc/timezone
# RUN命令:构建过程中执行,常用于安装软件包
RUN echo 'nameserver 8.8.8.8' >> /etc/resolv.conf \
&& sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories \
&& apk add --update-cache bash \
&& apk add bash \
&& apk add nodejs && apk add npm \
&& npm config set registry https://registry.npm.taobao.org
# 指定工作目录,用绝对
WORKDIR /app
# 定义环境变量
ENV NODE_ENV=production
# 从宿主机拷贝www.js和entrypoint.sh到容器
COPY ./app /app
# 与COPY类似,但ADD自带解压功能
#ADD ./x.tar.xz /app
# 配置entrypoint入口脚本
RUN chmod a+x ./entrypoint.sh
# 容器启动后执行的命令,且不可被docker run提供的参数覆盖
ENTRYPOINT ["/bin/sh", "./entrypoint.sh"]
# 容器启动后默认执行的命令,可被docker run后面的参数代替
#CMD ["/bin/sh"]
# 暴露端口
EXPOSE 3000
示例相关文件:
./app/www.js
// node server
var http = require('http')
http.createServer((req, res) => {
res.end('hello world!')
}).listen(3000)
console.log('node server is running at 3000...')
./app/entrypoint.sh
#!/bin/bash
node /app/www.js
构建镜像:
$ docker build -t myimage:latest . # 镜像名需小写,'.'当前目录查找Dockerfile配置
新建并启动容器:
$ docker run -dit -p 8000:3000 --dns=8.8.8.8 --name 容器名 --restart always myimage:latest
2.)Dockerfile构建总结
a. 构建时下载不了软件包,说明容器dns不对,需修改/etc/resolv.conf
b. alpine镜像默认sh终端,需安装bash
c. 建议一个容器只运行单个应用,多个应用见下文compose部署
d. Docker镜像构建是分层,将多个RUN指令合并
e. -v持久化路径时,若宿主机路径是新建的,容器路径内容会被清空
f. 当ENTRYPOINT与CMD使用exec参数时需双引号
g. 添加.dockerignore,提高编译速度:
.git/
node_modules/
四、多应用容器部署
Docker Compose是一个管理多容器应用的工具
1、docker-compose安装
Compose下载地址: https://get.daocloud.io/#inst...
$ curl -L https://get.daocloud.io/docker/compose/releases/download/1.24.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
$ chmod +x /usr/local/bin/docker-compose
# 测试
$ docker-compose -v
2、docker-compose命令
默认需在当前目录有个docker-compose.yml文件
# 查看yml配置
$ docker-compose config
# 查看当前项目多容器状态
$ docker-compose ps
# 启动/重启/停止已存在的容器(对yml配置变化无感)
$ docker-compose start | restart | stop
# 创建并启动容器(容器不存在或yml配置变化时触发)
$ docker-compose up -d # -d后台运行
# 对于已存在且配置未变化的容器,默认不动作,可以通过参数强制新建重启,但过于浪费
$ docker-compose up -d --force-recreate
# 兼容方案:配置变化时重建,不变则重启(适用于自动化部署)
$ docker-compose stop && docker-compose up -d
# 手动指定配置,多个-f会合并,相同项后面会覆盖前面
$ docker-compose -f a.yml -f b.yml up -d
# 先通过Dockerfile构建镜像,再启动容器
$ docker-compose up -d --build
# 停止并移除容器
$ docker-compose down
3、docker-compose配置
在项目根目录下,新建docker-compose.yml文件
1.)配置示例
以下为nginx+node+mongo+redis联合容器的配置,项目名假设为proj
version: '3'
services:
web:
image: nginx
container_name: proj-web
restart: always
ports:
- 1081:81
volumes:
- ./bin/nginx.conf:/etc/nginx/conf.d/web.conf
- ./web/dist:/app
command: ['nginx', '-g', 'daemon off;']
links:
- server
server:
image: keymetrics/pm2
container_name: proj-server
restart: always
ports:
- 1082:82
volumes:
- ./server:/app
working_dir: /app
environment:
- MONGO_SERVER=mongo
- MONGO_PORT=27017
- REDIS_SERVER=redis
- REDIS_PORT=6379
command: npm start
links:
- mongo
- redis
mongo:
image: mongo
container_name: proj-mongo
restart: always
ports:
- 10017:27017
volumes:
- ./mongo/configdb:/data/configdb
- ./mongo/db:/data/db
command: mongod --auth
redis:
image: redis
container_name: proj-redis
restart: always
ports:
- 10379:6379
volumes:
- ./redis/data:/data
- ./bin/redis.conf:/usr/local/etc/redis.conf
command: redis-server /usr/local/etc/redis.conf
需要注意的:
a.) command支持exec和shell两种模式(见上面的web和server)
b.) nginx、pm2等进程需加--no-daemon参数使其在前台运行,以保证容器不退出
c.) npm start需要设置工作目录
d.) links后,在容器可直接把服务名做为一个hostname访问,如下:
# nginx反向代理
proxy_pass http://server:81/;
# mongo连接
mongodb://mongo:27017/xxxDB
# node容器可先设置环境变量,再动态获取
'mongodb://www:123456@' + process.env.MONGO_SERVER + ':' + process.env.MONGO_PORT + '/xxxDB'
2.)容器部署
在docker-compose.yml同目录下,运行以下命令,创建并启动容器:
$ docker-compose up -d
默认up命令只有当容器不存在或yml文件配置变化时才触发重建重启容器,而当node等web项目本身有更新并不会自动重启,解决方案:
$ docker-compose stop && docker-compose up -d
3.)mysql容器配置
官方mysql容器相对智能,可以自动帮助创建root密码、web数据库、用户/密码、用户权限及初化配置, 参考>>
mysql:
image: mysql
container_name: proj-mysql
restart: always
ports:
- 10306:3306
environment:
MYSQL_ROOT_PASSWORD: ${dbRootPass}
MYSQL_USER: ${dbUser}
MYSQL_PASSWORD: ${dbPass}
MYSQL_DATABASE: ${dbName}
volumes:
- ./bin/my.cnf:/etc/my.cnf
- ./bin:/docker-entrypoint-initdb.d/
- ./mysql/db:/var/lib/mysql
command: --default-authentication-plugin=mysql_native_password
compose配置支持变量替换,只需同目录下配置.env文件:
dbRootPass=root123
dbUser=www
dbPass=123456
dbName=xxxDB
项目下./bin/my.cnf配置:
[mysqld]
user=mysql
default-storage-engine=INNODB
character-set-server=utf8
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
项目下./bin/init.sql,用来放一些建表等初始化sql,如下:
use xxxDB;
create table xxxTable
(
id int(11) auto_increment primary key not null,
name varchar(45),
update_time datetime
);
需要注意的:
environment:设置的root密码、数据库、数据库权限用户/密码仅在数据库第一次创建时生成,不会随容器的重建或重启而变化
volumes:冒号后面的内容为容器约定路径,不要修改
command:给内置的mysqld命令添加了一个参数,用来解决从mysql5.7版本之后采用了caching_sha2_password验证方式的兼容问题
4.)Dockerfile混合部署
除了使用第三方已有的镜像,也可以通过Dockerfile配置自己的镜像,实时构建后再启动容器
myapp:
container_name: proj-myapp
build: . # 读取当前目录下Dockerfile文件
部署时需要添加--build参数
$ docker-compose up -d --build
五、可视化容器管理工具
Portainer是一个轻量级的Docker环境UI界面管理系统
1、快速部署
$ docker volume create portainer_data # 在宿主机创建持久化目录
$ docker run -d -p 9000:9000 --name portainer --restart always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer
2、相关配置
1.)交互模式
创建容器时,在高级设置里,Console项记得勾选交互模式,否则无法使用控制台
- [x] Interactive & TTY (-i -t)
2.)入口命令
在容器高级设置里,command里的shell命令必须单个加引号,如:
Command: 'pm2' 'start' './www.js' '--no-daemon'
Working Dir: /app
3.)volume添加
portainer中volume默认在/var/lib/docker/volumes下,通过点击bind按钮修改/自定义对应的host路径
4.)查看应用日志
点开Container status下面的logs,在日志界面关掉
Auto-refresh logs自动刷新功能