什么是Docker?
Docker是一种虚拟容器技术,本质上是运行在宿主机上的进程(共享内核),它通过命名空间(Namespaces)实现了资源隔离,并通过CGroups(Control Groups)实现了资源的限额,同时通过写时复制(copy-on-write)实现了高效的文件操作。
Namespaces隔离:文件系统、网络、进程间通信、主机名、进程号、用户权限
CGroups限额:CPU、内存、磁盘 I/O 和带宽
copy-on-write:多个容器之间共享一份镜像
Docker优势:持续集成、版本控制、可移植性、隔离性和安全性
一、docker安装
docker官网:
https://docs.docker.com/get-s…
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 容器名 镜像名
更多参数:映射端口、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 原镜像
三、构建镜像
一般可以直接使用官方registry提供的镜像,也可以DIY自己应用场景的镜像,通过手动构建和Dockerfile配置创建两种方式。
1、手动构建镜像
用基础镜像创建一个容器,进入到容器,手动安装好应用和服务,然后用下面的命令将容器创建出镜像:
$ docker commit 容器名 新镜像名
2、Dockerfile构建:
1.)自定义一个alpine镜像
docker中最小的镜像是一个大小为0的空镜像—scratch(也是docker保留关键字)
下面通过最简单的示例,构建出一个很小的alpine镜像(同官方一样只有5M左右):
- 先下载alpine rootfs内核
$ curl -o alpine.tar.gz https://mirrors.aliyun.com/alpine/v3.10/releases/x86_64/alpine-minirootfs-3.10.2-x86_64.tar.gz
- 新建Dockerfile,配置如下:
FROM scratch
MAINTAINER hoby<w.hoby@qq.com>
ADD ./alpine.tar.gz /
CMD ["/bin/sh"]
- 构建镜像,创建容器
# 构建镜像:
$ docker build -t alpine:my . # "."表示当前目录
# 创建容器
$ docker run -dit --name 容器名 alpine:my
2.)标准的Dockerfile配置
下面是一个基于alpine的node运行环境的实例:
# 基础镜像源
FROM alpine
# 创建者信息
MAINTAINER hoby <w.hoby@qq.com>
# 修复时区
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.aliyun.com/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 echo -e '#!/bin/bash \nnode /app/www.js' > entrypoint.js \
&& 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...')
构建镜像:
$ docker build -t myimage:latest . # 镜像名需小写
新建并启动容器:
$ docker run -dit -p 8000:3000 --dns=8.8.8.8 --name 容器名 --restart always myimage:latest
3.)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/
3、搭建私有镜像库
构建好的镜像可以放在自己的私有registry中
# 本地搭建一个私有registry容器
$ docker run -d -p 5000:5000 --name registry registry:latest
# 给本地镜像打标签
$ docker tag myimage localhost:5000/myimage
# 推送
$ docker push localhost:5000/myimage
# 查看私有镜像数
$ curl localhost:5000/v2/_catalog
四、多应用容器部署
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: mhart/alpine-node
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自动刷新功能