容器管理工具 docker
的出现使开发及运行环境的配置变得更加便利,服务器运维更高效,也成为了后端工程师必须要掌握的效率工具,我们在这里总结一下它的具体使用,关于 Linux
下安装 docker
相关请看前面一篇:CentOS7安装Docker配置服务端和容器自启动,这里我们将详细介绍 docker
的使用, dockerfile
的编写规则和实例, docker-compose
工具的使用和实例,基本上想学会 docker
,看这一篇就够了。
Docker基本操作
镜像操作
配置阿里云镜像加速器
为了提高官方镜像拉取速度,我们使用阿里云提供的镜像加速器。
进入容器镜像服务
=> 镜像加速器
,获取自己的加速器地址,替换到下面,运行下面的命令即可。
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://*****.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
拉取镜像
比如我们要拉取 php
官方镜像,先到 hub.docker.com上找到我们想要的
php 镜像版本(tags),可以看到,这里有非常多的满足不同需求的版本镜像,我们选
7.1-fpm`,我们的拉取命令就是:
docker pull php:7.1-fpm
不指定 tag
从 hub
拉取镜像可能会报错,比如:
[root@localhost docker]# docker pull opensips/opensips
Using default tag: latest
Error response from daemon: manifest for opensips/opensips:latest not found
这里是因为 pull
默认使用 latest
作为镜像 tag
,但这个镜像下没有这个未指定这个 tag
,所以我们需要手动指定一个存在的 tag
拉取。
[root@localhost docker]# docker pull opensips/opensips:2.4
拉取的镜像并不总能直接满足需求,大部分时候我们需要创建自定义镜像,看下面的 Dockerfile的使用
部分。
提交镜像
第一步:在 https://hub.docker.com/
注册账户并创建仓库;
第二步: 为镜像设置 tag
;
比如我要把本地的php71镜像提交到仓库 hsu1943/php71:latest
:
docker tag php:7.1 hsu1943/php71:latest
第三步:推送镜像:
docker push hsu1943/php71:latest
容器操作
查看所有容器(包括已停止的)
[root@localhost /]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
03861a98f878 php:7.1 "docker-php-entrypoi…" 11 days ago Up 33 minutes 0.0.0.0:9000->9000/tcp php71
d3e84fdcd630 nginx:1.14 "nginx -g 'daemon of…" 12 days ago Up 33 minutes 0.0.0.0:80->80/tcp, 0.0.0.0:443->433/tcp nginx114
0d47cf1170a8 redis:4.0 "docker-entrypoint.s…" 12 days ago Up 33 minutes 0.0.0.0:6379->6379/tcp redis4
076c3f7b2d07 mysql:5.7 "docker-entrypoint.s…" 12 days ago Up 33 minutes 0.0.0.0:3306->3306/tcp, 33060/tcp mysql57
24ecc15d6bda opensips/opensips:2.4 "/run.sh" 3 weeks ago Exited (137) 3 weeks ago opensips
重新启动容器,以下的 ID
指的是上面的 CONTAINER ID
或者是 NAMES
docker restart ID
关闭容器
docker stop ID
强制关闭容器
docker kill ID
删除容器
docker rm ID
查看容器日志
docker logs ID
进入容器并打开终端
docker exec -it ID /bin/bash
查询容器ip地址
docker inspect --format '{{ .NetworkSettings.IPAddress }}' ID
容器中 vi
, ipconfig
, ping
命令报错:
command not found
,由于一般镜像未安装这些工具,需要我们安装,当然也可以在自己的镜像 Dockfile
中加入。
apt-get update
#vim
apt-get install vim
#ipconfig
apt install net-tools
#ping
apt install iputils-ping
设置容器网络:
使用docker network进行网络相关配置
# 新建网络
[root@localhost /]# docker network create --subnet=172.18.0.0/16 mynetwork
c387a6bdaf315fb156bfddea2edbe772bfa2981e55ee5f23bdbf5aa38a669903
# 查看已有网络
[root@localhost /]# docker network ls
NETWORK ID NAME DRIVER SCOPE
11a662a47a82 bridge bridge local
1cde9f1dc93e host host local
c387a6bdaf31 mynetwork bridge local
0d42b5bfe5e1 none null local
# 查看网络连接情况
[root@localhost /]# docker network inspect mynetwork
# 让容器连接到指定网络指定ip
[root@localhost /]# docker network connect --ip 172.18.0.8 --alias mysql_test mynetwork containerID
# 断开容器网络连接
[root@localhost /]# docker network disconnet mynetwork containerID
# 移除网络,需要该网络中的容器全部断开连接才可以
[root@localhost /]# docker network rm mynetwork
运行容器:
使用 docker run
直接来运行一个基于官方镜像 mysql:5.7
的容器,根据参数说明,我们就知道如何启动一个容器了。
docker run -d -p 3306:3306 --privileged=true
-v /home/docker/mysql/conf/my.cnf:/etc/mysql/my.cnf
-v /home/docker/mysql/data:/var/lib/mysql
-v /home/docker/mysql/log:/var/log/mysql
--restart=always
--network mynetwork --network-alias mysql
-e MYSQL_ROOT_PASSWORD=123456 --name mysql mysql:5.7
参数说明:
-d 后台运行
-p 开放端口 格式|主机端口:容器端口
--privileged 提供权限
-v 文件挂载
--restart=always 保持在线
--network mynetwork 使用自定义网络mynetwork
--network-alias mysql 网络别名mysql
-e MYSQL_ROOT_PASSWORD=123456 配置环境变量
--name mysql mysql:5.7 容器名称
备份 mysql
容器数据库:
docker exec mysql sh -c 'exec mysqldump --all-databases -uroot -p"123456"' > /some/path/on/your/host/all-databases.sql
从临时容器中获取配置文件
在容器构建过程中需要配置文件挂载,手上没有现成的配置文件?先跑一个临时容器,把默认的配置文件拷贝出来,然后根据自己的情况编辑好配置文件,挂载到使用的容器中去,就可以大道快速部署的目的了。
$ docker run --name tmp-nginx-container -d nginx
$ docker cp tmp-nginx-container:/etc/nginx/nginx.conf /host/path/nginx.conf
$ docker rm -f tmp-nginx-container
# 这里使用了cp命令,在主机和容器之间拷贝文件
Dockerfile的使用
镜像库里的镜像并不能满足所有人的需求,需要根据不同的项目需要来制作自己的镜像, Dockerfile
就很方便的是我们可以以某个镜像为基础(基础镜像),制作一个完全满足自己需求的自定义镜像了供项目需要。具体 Dockerfile
的使用技巧,可以参考这里:Dockerfile reference,这里大概总结一下常用操作和基本格式。
在这之前,先了解一下创建镜像。
docker build命令
# build命令默认上下文是当前目录
docker build
# 指定生成镜像的名称以及tag,可以多次指定以生成多个
docker build -t shykes/myapp:1.0.2
docker build
的工作原理(上下文)解析, Docker
在运行时分为 Docker daemon
(服务端守护进程)和客户端工具。 Docker daemon
提供了一组 REST API
,被称为 DockerRemote API
,而如 docker
命令这样的客户端工具,则是通过这组 API
与 Docker daemon
交互,从而完成各种功能。因此,虽然表面上我们好像是在本机执行各种 docker
功能,但实际上,一切都是使用的远程调用形式在服务端( Docker daemon
)完成。也因为这种 C/S
设计,让我们操作远程服务器的 Docker daemon
变得轻而易举。
当我们进行镜像构建的时候,并非所有定制都会通过 RUN
指令完成,经常会需要将一些本地文件复制进镜像,比如通过 COPY
指令、 ADD
指令等。而 docker build
命令构建镜像,其实并非在本地构建,而是在服务端,也就是 Docker daemon
中构建的。那么在这种客户端/服务端的架构中,如何才能让服务端获得本地文件呢?
这就引入了上下文的概念。当构建的时候,用户会指定构建镜像上下文的路径, docker build
命令得知这个路径后,会将路径下的所有内容打包,然后上传给 Docker daemon
。这样 Docker daemon
收到这个上下文包后,展开就会获得构建镜像所需的一切文件。
# 会将上下文(context)发送给Docker daemon
docker build .
Sending build context to Docker daemon 6.51 MB
...
docker build
命令的上下文还可以是 git
仓库,压缩文件甚至是文本文件。更多的关于 docker build
命令相关看这里:docker build。
千万不要在根目录之类的目录作为上下文,一般使用一个空目录,把
Dockerfile
和需要的文件放在该目录下进行创建。
在 Dockerfile
中使用一些操作(比如 COPY
)将上下文目录中的文件添加到镜像中,可以使用 .dockerignore
文件指定要忽略的目录或者文件,不知道如何编写一个 .dockerignore
文件?传送门。
默认会使用上下文目录下的 Dockerfile
,也可以在命令中指定它:
$ docker build -f /path/to/a/Dockerfile .
在执行 Dockerfile
前, Docker daemon
会一条条去校验其中的指令,如果有错误将会提示错误并停止执行。
Docker daemon
会一条一条的执行指令,每一条产生一个新的 层
,每一层是独立存在,所以在上一个指令中的 cd /tmp
对后面的指令没有影响,为了提高执行效率,应该尽量将同一类的指令放到一起执行,减少 层
,在执行过程中,默认会使用缓存,也就是如果之前有执行过,生成的 层镜像
和现在需要的是一样的,那就直接用缓存了。
Dockerfile格式
以 #
开头后面视为注释(除解析器指令); Dockerfile
指令不区分大小写,不过一般约定指令使用大写,与参数区分;
FROM:必须使用 FROM
指令开头,来指定基础镜像;
- 镜像可以是任意有效的镜像 – 这个很容易从公共仓库拉取一个镜像。
- FROM必须是Dockerfile中的首个非注释指令。
- FROM可以在单个Dockerfile中出现多次,这样可以创建多个镜像。只需记下在每个新的FROM命令之前由提交输出的最后一个图像ID。
- tag或digest值是可选的。如果都不指定,那么默认是latest。如果找不到tag的值将返回错误。
FROM <image>
FROM <image>:<tag>
FROM <image>@<digest>
MAINTAINER:设置生成这个镜像的作者。
MAINTAINER hsu1943 "88888888@qq.com"
ENV:声明环境变量,可以在其他指令中使用;
- 在
Dockerfile
引用环境变量可以使用$variable_name
或${variable_name}
。它们是等同的,其中大括号的变量是用在没有空格的变量名中的,如${foo}_bar
。 -
${variable_name}
变量也支持一些标准的bash
修饰符,如:-
${variable:-word}
表示如果variable
设置了,那么结果就是设置的值。否则设置值为word
。 -
${variable:+word}
表示如果variable
设置了,那么结果是word
值,否则为空值
-
-
word
可以是任意的字符,包括额外的环境变量。 - 转义符可以添加在变量前面:
$foo
或者${foo}
,例如,会分别转换为$foor
和${foo}
。
FROM busybox
ENV foo /bar
ENV PHP_INI_DIR /usr/local/etc/php
WORKDIR ${foo} # WORKDIR /bar
ADD . $foo # ADD . /bar
COPY $foo /quux # COPY $foo /quux
COPY:将上下文目录中的文件复制到docker镜像中
这个命令很直观,也很可靠,在这里大家可能会想到 ADD
命令,这个命令除了复制文件以外还会做更多(复制远程文件,可以自动解压缩),但我们还是建议直接用 COPY
就够了,降低复杂度,提高成功率。
对于目录而言, COPY
只复制目录中的内容而不包含目录自身,所以当你需要复制包含目录的话,应该指定目标路径目录。
COPY docker-php-source /usr/local/bin/
ENTRYPOINT和CMD:设置容器启动时要执行的命令
这两个命令功能上是很相似的,所以也很容易混淆,基本原则:
- Dockerfile中至少有一个(
ENTRYPOINT
或者CMD
),不然回会报错; - 多个
ENTRYPOINT
或多个CMD
只会执行最后一条; - 如果
ENTRYPOINT
使用了shell
模式,CMD
指令会被忽略; - 如果
ENTRYPOINT
使用了exec
模式,CMD
指定的内容被追加为ENTRYPOINT
指定命令的参数; - 如果
ENTRYPOINT
使用了exec
模式,CMD
也应该使用exec
模式。
对于 CMD
和 ENTRYPOINT
的设计而言,多数情况下它们应该是单独使用的。当然,有一个例外是 CMD
为 ENTRYPOINT
提供默认的可选参数。
如果还是不清楚,看看官方给出的这个图,大概就能理解了:
LABEL:添加关于镜像的一些信息
LABEL version="1.0"
LABEL description="This text illustrates
that label-values can span multiple lines."
LABEL maintainer="SvenDowideit@home.org.au" # 代替MAINTAINER的使用,推荐
因为每一个LABEL都会生成一个新的镜像层,所以建议将LABEL放到一起,可以使用换行达到目的,使用
docker inspect
可以查看镜像的 LABEL
s,对于同名(key)的情况,后面的LABEL会覆盖前面的,包括FROM指定的基础镜像中的,多个LABEL合并一起:
LABEL version="1.2.0"
description="about lnmp"
maintainer="SvenDowideit@home.org.au"
other="other value"
EXPOSE:声明容器运行时应该打开的端口
这个指令告诉要运行 docker run
这个镜像的运维人员本镜像哪些端口需要映射,在 run
的之后可以通过 -p
来指定端口映射,或者用 -P
随机映射端口,随机映射会将 EXPOSE
声明过的端口映射出来。
对于在同一个 docker network
中的容器,无需打开端口他们之间就可以通过任何端口来访问彼此。
EXPOSE 9000
USER:指定执行后面RUN,CMD,ENTRYPOINT的用户(组)
使用USER指定用户时,可以使用用户名、UID或GID,或是两者的组合。当不需要管理员权限时,可以通过该命令指定运行用户。一般会在之前创建所需要的用户。
运行容器 docker run
时,可以通过 -u
参数来覆盖所指定的用户。
WORKDIR:指定工作目录
可以为后面的 RUN
, CMD
, ENTRYPOINT
, COPY
以及 ADD
指令指定工作目录,目录中可以解析之前使用 ENV
指定的环境变量。
ENV DIRPATH /var
WORKDIR $DIRPATH/www/html
echo pwd
# 会输出 /var/www/html
ARG:构建参数,指定在build时可以传递过来的变量
使用 ARG
指定的变量可以在 docker build
中通过 --build-arg <varname>=<value>
的形式进行传递,这区别于 ENV
指定的环境变量,环境变量无法在 build
时传递进来。
ARG user1=someuser # 没有传递进来就使用默认值
ARG buildno=1
可以将 ARG
和 ENV
结合一起使用:
ARG var
ENV var=${var}
ONBUILD:构建子镜像时在FROM之后立即执行在的任务
本镜像并不执行这个指令,而是在子镜像(下一层)中去执行。
# 父容器中Dockerfile内容
FROM busybox
ONBUILD RUN echo "第二次构建(子构建)才执行"
# 构建父镜像
docker build -t father .
# 构建过程中不会打印"第二次构建(子构建)才执行"
创建子容器
# 子容器中Dockerfile内容
FORM father
# 构建子镜像
docker build -t child .
# 构架过程中打印了"第二次构建(子构建)才执行"
VOLUME:指定容器数据挂载点
指定容器中需要挂载到宿主机的挂载点,在宿主机会生成对应的目录(目录名随机)存放数据,需要注意这里跟 docker run
中可以指定宿主机目录不同, Dockerfile
中的挂载无法指定宿主机目录,这是为了保证可移植性,规定的目录并不一定在每个宿主机都存在。
VOLUME /var/log/mysql
VOLUME ["/var/log/mysql", "/data2"]
更多关于 VOLUME
(共享 --volumes-from
)的知识可以参考官方文档。
Dockerfile小技巧:apt使用国内源
# Dockfile开头加一行,使用国内debian源
COPY ./sources.list /etc/apt/sources.list
# 在Dockerfile同目录新建sources.list,内容:
deb http://mirrors.ustc.edu.cn/debian/ stretch main non-free contrib
deb http://mirrors.ustc.edu.cn/debian/ stretch-updates main non-free contrib
deb http://mirrors.ustc.edu.cn/debian/ stretch-backports main non-free contrib
deb-src http://mirrors.ustc.edu.cn/debian/ stretch main non-free contrib
deb-src http://mirrors.ustc.edu.cn/debian/ stretch-updates main non-free contrib
deb-src http://mirrors.ustc.edu.cn/debian/ stretch-backports main non-free contrib
deb http://mirrors.ustc.edu.cn/debian-security/ stretch/updates main non-free contrib
deb-src http://mirrors.ustc.edu.cn/debian-security/ stretch/updates main non-free contrib
# 不同版本的debian修改stretch即可
Dockerfile实例:
FROM php:7.1-fpm
# 使用国内源
ADD sources.list /etc/apt/
# install any custom system requirements
RUN apt-get update && apt-get install -y --no-install-recommends
libfreetype6-dev
libjpeg-dev
libjpeg62-turbo-dev
libmcrypt-dev
libpng-dev
libpq-dev
libicu-dev
libz-dev
libbz2-dev
libmemcached-dev
libxml2-dev
git
&& rm -rf /var/lib/apt/lists/*
# Install various PHP extensions
RUN docker-php-ext-configure bcmath --enable-bcmath
&& docker-php-ext-configure pcntl --enable-pcntl
&& docker-php-ext-configure pdo_mysql --with-pdo-mysql
&& docker-php-ext-configure pdo_pgsql --with-pdo-pgsql
&& docker-php-ext-configure mbstring --enable-mbstring
&& docker-php-ext-configure soap --enable-soap
&& docker-php-ext-install
bcmath
intl
mbstring
mcrypt
mysqli
pcntl
pdo_mysql
pdo_pgsql
soap
sockets
zip
iconv
&& docker-php-ext-configure gd
--enable-gd-native-ttf
--with-jpeg-dir=/usr/lib
--with-freetype-dir=/usr/include/freetype2
&& docker-php-ext-install gd
&& docker-php-ext-install opcache
&& docker-php-ext-enable opcache
&& pecl install xdebug redis
&& docker-php-ext-enable xdebug redis
&& rm -rf /tmp/pear
# AST
RUN git clone https://github.com/nikic/php-ast /usr/src/php/ext/ast/
&& docker-php-ext-configure ast
&& docker-php-ext-install ast
# ICU - intl requirements for Symfony 由于下载巨慢,改成直接COPY压缩包
# Debian is out of date, and Symfony expects the latest - so build from source, unless a better alternative exists(?)
# RUN curl -o /tmp/icu.tar.gz -L http://download.icu-project.org/files/icu4c/63.1/icu4c-63_1-src.tgz
COPY ./icu4c-58_2-src.tgz /tmp/icu.tar.gz
RUN tar -zxf /tmp/icu.tar.gz -C /tmp
&& (
cd /tmp/icu/source
&& ./configure --prefix=/usr/local
&& make
&& make install
)
&& rm -rf /tmp/icu
&& rm /tmp/icu.tar.gz
&& docker-php-ext-configure intl --with-icu-dir=/usr/local
&& docker-php-ext-install intl
# Install the php memcached extension
RUN curl -L -o /tmp/memcached.tar.gz "https://github.com/php-memcached-dev/php-memcached/archive/php7.tar.gz"
&& mkdir -p memcached
&& tar -C memcached -zxvf /tmp/memcached.tar.gz --strip 1
&& (
cd memcached
&& phpize
&& ./configure
&& make -j$(nproc)
&& make install
)
&& rm -r memcached
&& rm /tmp/memcached.tar.gz
&& docker-php-ext-enable memcached
# set timezone
RUN rm /etc/localtime
&& ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
#composer
RUN curl -sS https://getcomposer.org/installer | php --
--install-dir=/usr/bin
--filename=composer
这个 PHP7.1
的 Dockerfile
以官方镜像 php:7.1-fpm
为计出镜像,安装了常用的工具及扩展,设置时区及 composer
,开包即用,非常方便。
为了更好的理解 build
命令的上下文,看一下当前目录结构:
[root@localhost docker]# tree php7
php7
├── Dockerfile
├── icu4c-58_2-src.tgz
└── sources.list
0 directories, 3 files
docker-compose的使用
用于定义和运行多个 docker
容器的工具,为运维工作服务器的部署和自动化运维提供了极大的便利,通过一个 docker-compose.yml
命令就可以实现多个
安装docker-compose
安装
curl -L "https://github.com/docker/compose/releases/download/1.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
添加执行权限
chmod +x /usr/local/bin/docker-compose
关于 docker-compose
的使用,以及 docker-compose.yml
文件的书写格式,见:
docker-compose官方文档
docker-compose.yml实例
version: '3'
services:
nginx:
image: nginx:1.14
restart: always
# 端口映射
ports:
- "80:80"
- "443:433"
environment:
- TZ=Asia/Shanghai
# 依赖关系
depends_on:
- "php"
# 数据卷
volumes:
# 映射主机./conf.d目录wwwroot目录nginx.conf文件
- $PWD/nginx/conf.d:/etc/nginx/conf.d
- $PWD/wwwroot:/usr/share/nginx/html
- $PWD/nginx/nginx.conf:/etc/nginx/nginx.conf
- $PWD/logs/nginx:/var/log/nginx
networks:
- app_net
# 容器名称
container_name: "nginx114"
php:
build: ./php7
restart: always
# image指定build 上下文./php7目录下Dockerfile生成镜像的名称
image: php:7.1
# php-fpm记录日志用
cap_add:
- SYS_PTRACE
ports:
- "9000:9000"
volumes:
# 网站文件目录,配置目录
- $PWD/wwwroot:/var/www/html
- $PWD/php:/usr/local/etc
networks:
- app_net
container_name: "php71"
mysql:
image: mysql:5.7
restart: always
ports:
- "3306:3306"
# 环境变量
environment:
# mysql密码
- TZ=Asia/Shanghai
- MYSQL_ROOT_PASSWORD=123456
volumes:
# 挂载数据库文件,配置文件
- $PWD/mysql/data:/var/lib/mysql
- $PWD/mysql/conf:/etc/mysql
- $PWD/logs/mysql:/var/log/mysql
networks:
- app_net
container_name: "mysql57"
redis:
image: redis:4.0
restart: always
# 如果不需要外网访问,使用"127.0.0.1:6379:6379"来限制
ports:
- "6379:6379"
environment:
- TZ=Asia/Shanghai
volumes:
- $PWD/redis/data:/data
- $PWD/redis/redis.conf:/etc/redis/redis.conf
networks:
- app_net
container_name: "redis4"
networks:
# 配置docker network
app_net:
driver: bridge
ipam:
config:
# 子网络
- subnet: 178.18.0.0/16
这是一个完整的 nginx + php + mysql + redis
多容器的运行环境,结合上面 php7.1
的 Dockerfile
实例只需要按需要修改挂载目录及配置文件即可运行。
标题:docker,Dockerfile,docker-compose操作指南及最佳实践
原文链接:https://beltxman.com/2417.html
若无特殊说明本站内容为 行星带 原创,未经同意请勿转载。
感谢博主,文章总结得很全面,受益匪浅
有用就行!
挺不错的博客 留个足迹 博客已经收录在 https://manman.qian.lu/bokeshu
感谢收录