docker命令升级与docker环境构建
内容来源为六星教育,这里仅作为学习笔记
容器
基础操作
我们可以基于镜像与构建容器
如下为创建过程
容器类型:
- 交互型容器:运行在前台,通常会制定有交互的控制台,可以给容器输入,也可以得到容器的输出。创建该日期的终端被关闭,在容器内部使用exit命令或者调用docker stop 、docker kill命令 后,容器会停止
- 后台型容器:运行在后台,创建启动之后就与终端无关。即便终端关闭了,改后台容器也依然存在,只有执行docker stop或者docker kill命令时候才能够使容器变成停止状态
我们可以进入容器中的系统:
如上命令我们就相当于进入容器中的系统了,同时我们也可以启动容器中的redis
我们可以查看容器中的进程,通过如下命令:
查看镜像的历史
~ docker history 镜像
export 与 import
docker的流行与它对容器的易分享和易移植密不可分。用户不仅可以把容器提交到公共服务器上,还可以将容器导出到本地文件系统中。同样我们也可以讲导出的容器重新导入到docker运行环境中。docker的导入和导 出分别由import命令和export命令完成。
docker export命令会把容器的文件系统以tar包的格式导出到标准输出,我们将其重定位到目标文件name.tar。将容器保存到本地文件也算是其持久化方式的一一种。 将容器保存到本地之后,我们就可以通过网络等方法 将tar包分享给他人。反过来,我们可以使用docker import命令 导人一个本地的tar包作为镜像:
接下来我们通过docker run构建容器:
第一次运行报错是因为docker的bug,因为没有一个前台进程在运行 而加上 bash,top等命令 就是跟docker一个挂起在前台的界面
save 与 load
docker save : 将指定镜像保存成 tar 归档文件。
docker save [OPTIONS] IMAGE [IMAGE…]
OPTIONS 说明:-o :输出到的文件。
两者对比
类型 | 导出的对象 | 导出文件大小 | 是否可回滚到历史层 |
---|---|---|---|
export & import | 将容器导出 | 小 | 否 |
save & load | 用来将一个或多个image打包 | 大 | 是 |
相对于文件大小来说,save方式导出的文件比export方式导出的文件大
正是因为save方式保存了镜像的历史和层(layer),使其可以层回滚,即回滚到之前的历史层,所以save方式导出的文件稍微大一些反观export方式,在导出过程中丢失所有的历史,导致其不可以层回滚,导出的文件会小 一些可以通过 docker history 镜像名 看到层关系
使用commit命令创建本地镜像
使用镜像创建并运行一个容器,实际上是在父镜像的基础上创建一个可读写的文件层级。我们在容器里所做的修改(包括安装新的应用程序、更改系统配置),都发生在这个层级上面。下面的一下列命令展示redis5镜 像上创建和运行一个容器,并在该容器上完成redis的安装或者做其他的软件也可以创建一个文件写入 redis5 test docker
等操作
然后我们使用commit命令讲容器里的所有修改提交到本地库中,形成一个全新的镜像;
commit命令后,返回一个长的字符串,这个字符串就是刚创建镜像的完整id,这个id也可以通过docker ps -l -q(用于获取最近创建的容器id) 命令得到。 -m参数是描述我们此创建images的信息(–author 参数用来指定 作者信息)
nginx环境构建
构建docker-lnrmp环境
构建lnrp主要是希望可以通过这个方式了解到docker的一些基本操作让大家可以更加好的熟悉docker
这儿有准备一份nginx的配置
user root;
worker_processes 1;
events {
worker_connections 1024;
}
http {
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
sendfile on;
keepalive_timeout 65;
server {
listen 80;
access_log /usr/local/nginx/logs/$host main;
location / {
root /www;
default_type text/html;
}
location ~ \.php/?.* {
default_type text/html;
#做php-fpm 配置,注意地址
root /www; #php-fpm容器当中的路径,不是nginx容器路径
fastcgi_index index.php;
fastcgi_pass 172.17.0.2:9000; #php容器端口
#为php-fpm指定的根目录
fastcgi_param SCRIPT_FILENAME $DOCUMENT_ROOT$fastcgi_script_name;
#注意是容器当中的位置
#定义变量 $path_info ,用于存放pathinfo信息
set $path_info "";
if ($fastcgi_script_name ~ "^(.+?\.php)(/.+)$") {
#将文件地址赋值给变量 $real_script_name
set $real_script_name $1;
#将文件地址后的参数赋值给变量 $path_info set
$path_info $2;
}
#配置fastcgi的一些参数
fastcgi_param SCRIPT_NAME $real_script_name;
fastcgi_param PATH_INFO $path_info;
include /usr/local/nginx/conf/fastcgi_params;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
关于nginx的dockerfile:
首先构建基础的dockerfile
FROM centos
RUN groupadd -r nginx && useradd -r -g nginx nginx
#添加centos源(先下载wget)
COPY ./epel-7.repo /etc/yum.repos.d/epel.repo
第一件事情就是添加centos的镜像源码;对于镜像源的添加方式有很多种
不了解的可以参考这个链接:https://blog.csdn.net/ctypyb2002/article/details/80635924
这里我们会采用自己手动copy文件的方式配置主要是了解copy和add这两个命令的作用和区别
copy与add
ADD: 向新镜像中添加文件,这个文件可以是一个主机文件,也可以是一一个网络文件,也 可以是一个文件夹。
从构建环境的上下文或远程URL复制文件至镜像。如果是从一个本地路径添加一个归档文件,那么它会被自动解压。由于ADD指令涵盖的功能相当广泛,一般最好还是使用相对简单的COPY指令来复制构建环境上下 文的文件和目录,并用RUN指令配合curl或wget来下载远程资源(这样还可以在同一个指令中处理和删除下载文件)。
ADD命令的第一个参数用来指定源文件 (夹),它可 以是文件路径、文件夹的路径或网络文件的URL地址。需要特别注意的是,如果是文件路径或文件夹路径,它必须是相对Dockerfile所在目录的相对路径。如果是一个文件URL,在创建镜像时,会先下载下来,然后再添加到镜像里去。第二个参数是文件需要放置在目标镜像的位置。如果源文件是gzip、bzip2或者xz形式的压缩文件,Docker会先解压缩,然后将文件添加 到镜像的指定位置。如果源文件是一一个通过URL指定的网络压缩文件,则不会解压。
COPY:
用于从构建环境的上下文复制文件至镜像。它有两种形式,COPY src dest 以及COPY[ “src”,“dest”],两者皆从上下文中的sre复制文件或目录至容器内的dest。如果路径中有空格的话,那么必须使用JSON数组 的格式。通配符可以用来指定多个文件或目录。请注意,你不能指定上下文以外的srC路径(例如./another di/mnyfile是不管用的)。
在dockerfile中添加相关的依赖
RUN yum update -y \
&& yum clean all \
&& yum makecache \
&& yum -y install gcc gcc-c++ autoconf automake make zlib zlib-devel net-tools openssl* pcre* wget \
&& yum clean all && rm -rf /var/cache/yum/*
RUN cd /data \
&& wget http://nginx.org/download/nginx-1.14.1.tar.gz \
&& tar -zxvf nginx-1.14.1.tar.gz \
&& cd nginx-1.14.1 \
&& ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx \
&& make && make install && rm -rf /data/nginx-1.14.1.tar.gz && rm -rf /data/nginx-1.14.1
COPY ./conf/nginx.conf /conf
#全局使用nginx,软链接
RUN ln -s /usr/local/nginx/sbin/* /usr/local/sbin
注意镜像过大
注意:我们的系统可能会因为我们的安装的疏忽造成镜像过大的问题
系统一般在进行yum安装之后会有一个cache的记录
yum命令会下载我们需要安装的软件然后进行缓存到默认的目录(当然这个目录我们是可以指定的)
- centos下执行yum install xxx后。
- 系统会从yum源下载rpm,将rpm放置到缓存目录下:
/var/cache/yum/
说明: yum源的不同则下载后存在的路径也有所不同,通常都是存放在packages目录下,如 /var/cache/yum/***/packages。
需要注意就是yum安装之后这些缓存不一定全部删除了有可能就会有些没有删除
CMD 与 ENTRYPOINT
CMD:用来设置启动容器时默认运行的命令,当然我们也可以通过指定的方式去覆盖。
我们在dockerfile中的内容如果是下面的情况
FROM alpine
CMD ["ls", "-a", "-l"]
测试
如果我们改一下docker run的命令让其执行其他命令
可以看到默认的被替换了
ENTRYPOINT:与CMD类似,它也是用来指定容器启动的时候默认运行的命令
FROM alpine
ENTRYPOINT ["ehco ENTRYPOINT"]
效果:
不难发现ENTRYPOINT和CMD的区别在于运行容器时添加在镜像名之后的参数,对ENTRYPOINT是拼接,而对于CMD命令则是覆盖。幸运的是,我们在运行容器的时候可以通过 --entrypoint来覆盖dockerfile中的命令
环境变量
ENV
设置容器运行的环境变量。在运行容器的时候,通过-e参数可以修改这个环境变量值,也可以添加新的环境变量: 在系统中可以执行如下命令就可以看到ENV的信息
格式有两种:
- ENV <key> <value>
- ENV <key>=<value> <key>=<value>…
这个指令很简单,就是设置环境变量而已,无论是后面的其他指令,如RUN
,还是运行是的应用,都可以直接使用这里定义的环境变量。
ENV VERSION=1.0 DEBUG=on \
NAME="Happy Feet"
这个例子中演示了如何换行,以及对含有空格的值用双引号括起来的办法,这和Shell下的行为是一致的。
定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。比如在官方node
镜像Dockerfile
中,就有类似这样的代码:
在这里先定义了环境变量NODE_VERSION
,其后的RUN
这层里,多次使用$NODE_VERSION
来进行操作定制。可以看到,将来升级镜像构建版本的时候,只需要更新7.2.0
即可,Dockerfile
构建维护变得更轻松了。
下列指令可以支持环境变量展开:
ADD
COPY
ENV
EXPOSE
LABEL
USER
WORKDIR
VOLUME
STOPSIGNAL
ONBUILD
可以从这个指令列表里感觉到,环境变量可以使用的地方很多,很强大。通过环境变量,我们可以让一份Dockfile
制作更多的镜像,只需使用不同的环境变量即可。
ARG
格式有两种:
- ARG <参数名>[=<默认值>]
构建参数和ENV
的效果一样,都是设置环境变量。所不同的是,ARG
所设置的构建环境的环境变量,在将来容器运行时是不会存在这些环境变量的。但是不要因此就使用ARG
保存密码之类的信息,因为docker history
还是可以看到所有值的。
Dockfile
中的ARG
指令是定义参数名称,以及定义其默认值。该默认值可以在构建命令docker build
中用--build-arg <参数名>=<值>
来覆盖。
在1.13之前的版本,要求--build-arg
中的参数名,必须在Dockerfile
中用ARG
定义过了,换句话说,就是--build-arg
指定的参数,必须在Dockerfile
中使用了。如果对应参数没有被使用,则会报错退出构建。从1.13开始,这种严格的限制被放开,不再报错退出,而是显示警告信息,并继续构建。这对于使用CI系统,用同样的构建流程构建不同的Dockerfile
的时候比较有帮助,避免构建命令必须根据每个Dockerfile的内容修改。
最终的dockerfile内容,构建镜像
FROM centos
RUN mkdir /data && mkdir /conf &&
RUN groupadd -r nginx && useradd -r -g nginx nginx
#修改时区
RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
ARG PHP_VERSION=7.2
#添加centos源(先下载wget)
COPY ./epel-7.repo /etc/yum.repos.d/epel.repo
#COPY
#RUN yum install -y wget
#RUN wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/Centos-7.repo
RUN yum update -y \
&& yum clean all \
&& yum makecache \
&& yum -y install gcc gcc-c++ autoconf automake make zlib zlib-devel net-tools openssl* pcre* wget \
&& yum clean all && rm -rf /var/cache/yum/*
#声明匿名卷
VOLUME /data
RUN cd /data \
&& wget http://nginx.org/download/nginx-1.14.1.tar.gz \
&& tar -zxvf nginx-1.14.1.tar.gz \
&& cd nginx-1.14.1 \
&& ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx \
&& make && make install && rm -rf /data/nginx-1.14.1.tar.gz && rm -rf /data/nginx-1.14.1
COPY ./conf/nginx.conf /conf
#全局使用nginx,软链接
RUN ln -s /usr/local/nginx/sbin/* /usr/local/sbin
#进入容器时默认打开的目录
WORKDIR /conf
#声明端口
EXPOSE 80
#容器启动的时候执行,在docker run过程当中是会被其他指令替代
#CMD ["/usr/local/nginx/sbin/nginx","-c","/conf/nginx.conf","-g","daemon off;"]
#执行一条指令
ENTRYPOINT ["/usr/local/nginx/sbin/nginx","-c","/conf/nginx.conf","-g","daemon off;"]
构建镜像
docker网络ip 与 EXPOSE
对于docker里面的容器来说(也就是系统),从系统来看是会独立的网络,同时也会有独立的ip,而如果说外部想要访问的话就需要暴露端口;可以通过dockerfile中EXPOSE参数或者 docker run -p
的方式
查看容器详细信息
EXPOSE
用来指明容器内进程对外开放的端口,多个端口之间使用空替隔力。运行容器通过参数-p(大写)即可将EXPOSE里所指定的端口映射到主机上另外的随机端口,容器或主机就可以通过映射后的端口与此容器通信。 同时,我们也可以通过-p (小写)参数将dockerfile中EXPOSE中没有列出的端口设置成公开的。
注意,expose只是开放端口
然后我们执行把命令改成这样,让容器的端口与宿主机的端口绑定的通过-p参数设置
~ docker run -d -p 8000:80 nginx
这个 -p 8000:80
是告诉宿主机用户访问8000端口转发至容器80上
- 例子:比如我们现在想让外部的工具远程连接内部的redis并进行操作,我们以之前的redis的dockerfile为实例
FROM centos:centos7
RUN groupadd -r redis && useradd -r -g redis redis
RUN yum update -y ; \
yum -y install gcc automake autoconf libtool make wget epel-release gcc-c++;
RUN mkdir -p /usr/src/redis; \
cd //usr/src/redis; \
wget https://github.com/antirez/redis/archive/5.0.7.tar.gz; \
tar -zxvf 5.0.7.tar.gz -C /usr/src/redis; \
rm -rf 5.0.7.tar.gz; \
cd /usr/src/redis/redis-5.0.7 && make ; \
cd /usr/src/redis/redis-5.0.7 && make install
EXPOSE 6379
CMD ["redis-server"]
- 构建redis
- 修改redis的配置增加对于远程的支持
数据卷和数据容器管理数据
这里需要注意,因为考虑到一个问题就是容器它可能会存在误删的情况,而如果我们的数据都在容器中这就会成为一个很大的问题;
应对这个问题docker就提出了一个解决方案,就是共享到宿主机;
如:docker run -v 挂载数据卷
格式:-v 容器目录 或 -v 本地目录:容器目录
根据上面的那个命令我们可以让本地的 /root/docker/redis5v/data
与docker容器中的 /data
地址进行绑定了;
我们可以测试一下是否如此
分别尝试在本地和docker容器中增加一个文件测试
dockerfile中的配置操作:
VOLUME ["<路径1>","<路径2>"…]
VOLUME <路径1>
之前我们说过,容器运行时应该尽量保持容器存储层不发生写操作,对呀数据库类需要保存动态数据的应用,其数据库文件应该保存于卷(volume)中。
为了防止运行时用户忘记将动态文件所保存目录挂载为卷,在Dockerfile
中,我们可以事先指定某些目录挂载为匿名卷,这样在运行时如果用户不指定挂载,其应用也可以正常运行,不会向容器存储层写入大量数据
VOLUME /data
这里的/data
目录就会在运行时自动挂载为匿名卷,任何向/data
中写入的信息都不会记录进容器存储层,从而保证了容器存储的无状态化。当然,运行时可以覆盖这个挂载设置,比如:
docker run -d -v mydata:/data xxx
在这行命令中,就使用了mydata
这个命名卷挂载到了/data
这个位置,替代了Dockerfile
中定义的匿名卷的挂载配置。
docker容器常用命令
~ docker logs 容器id或名称
查看容器里日志