Docker 安装使用实践

Docker 安装使用实践

安装

MAC OS

现在在Mac上安装Docker很简单,brew就可以。

brew cask install docker

貌似没有装cask的,会自动初始化,直接执行上面的命令即可。支持macOS Sierra 10.12以上系统。
也可以直接下载Stable或者Edge版本。dmg文件,直接下载好安装即可。
安装的唯一问题是,可能会在

Updating Homebrew...

这个状态等很久。搬了梯子也不行。找了一下资料,基本都是说更换brew源,而且看了好多页面,都是更换到同一套,我也就直接用了。

cd "$(brew --repo)"
git remote set-url origin https://mirrors.ustc.edu.cn/brew.git

#替换homebrew-core.git
cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core"
git remote set-url origin https://mirrors.ustc.edu.cn/homebrew-core.git
brew update


# 备用地址-1
cd "$(brew --repo)"
git remote set-url origin https://git.coding.net/homebrew/homebrew.git
brew update


# 备用地址-2
cd "$(brew --repo)"
git remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/brew.git
cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core"
git remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/homebrew-core.git
brew update

更新之后,也不算快,估计下载东西比较大。反正等着,自己执行完了。Applications里面就多了小鲸鱼了。
不知道更换了源对其他安装是否会有影响,如果有问题,就换回默认的:

#重置brew.git
cd "$(brew --repo)"
git remote set-url origin https://github.com/Homebrew/brew.git

#重置homebrew-core.git
cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core"
git remote set-url origin https://github.com/Homebrew/homebrew-core.git

上述配置内容,虽然我在很多页面看到都一样,但写的比较认真的是从这里

Mac 解决brew一直卡在Updating Homebrew

引用的。

centos

直接通过yum安装即可。

$ yum pudate
$ yum upgrade
$ yum install docker

可能都需要sudo执行。
安装完了启动docker服务:

$ systemctl start docker

需要root密码进行授权。

然后设置加速镜像

sudo mkdir -p /etc/docker

sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://gbpursha.mirror.aliyuncs.com"]
}
EOF

sudo systemctl daemon-reload

sudo systemctl restart docker

这样安装下来的是老版本,1.17什么的。新的docker分成了ee和ce,而且版本都是17.xxx,18.xxx这样了。安装新版本:

yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum makecache fast
rpm --import https://mirrors.aliyun.com/docker-ce/linux/centos/gpg
yum -y install docker-ce
systemctl enable docker
systemctl restart docker

需要先把老的docker卸载掉。需要remove掉:

yum remove docker
yum remove docker-common

新版本启动之后,执行docker命令,说.sock没权限。把当前用户加入docker组:

sudo gpasswd -a ${USER} docker

升级docker之后,发现有些images没法删除。用root用户直接删除:

/var/lib/docker/image/overlay2/imagedb/content/sha256

里面的东西。把所有的镜像都删除。重新启动docker服务。但有时候没啥鸟用,直接卸载,删除docker目录,重新安装。

安装指定版本docker

sudo yum -y install --setopt=obsoletes=0 docker-ce-${version}

通过如下命令看可以安装的版本:

yum list docker-ce.x86_64 --showduplicates

设置加速源

默认源pull镜像会想死。更换国内的加速源

https://gbpursha.mirror.aliyuncs.com

mac os从Preference直接加进去就行。
centos需要在/etc/docker/中建立daemon.json文件,加入如下内容:

{
  "registry-mirrors": ["https://gbpursha.mirror.aliyuncs.com"]
}

然后重启docker:

sudo systemctl restart docker

基本命令

mac的docker要用,需要在Applitions里面先运行docker小鲸鱼图标。
先把几个基础命令搞清楚,分清楚镜像、容器,怎么安装和运行。

  • 拉取镜像、安装容器并且运行
$ docker run -d -p 80:80 --name webserver nginx

run命令在指定镜像第一次启动的时候用,相当于执行了两个步骤,将镜像放入容器中(docker create),然后将容器启动,使之变成运行时容器(docker start)。
执行run命令,Docker 首先从本地主机上查找镜像是否存在,如果不存在,Docker 就会从镜像仓库 Docker Hub 下载公共镜像。
上述命令就是查找并安装一个叫nginx的镜像,并且把nginx端口映射到80上。同时为这个镜像起名叫webserver

  • 运行已经存在的容器
    运行已经安装好的容器,则使用:
$ docker start [CONTAINER ID]或者[NAMES]

需要知道容器的id或者名字。

  • 拉取镜像
docker pull httpd

或者其他的镜像名字。pull仅仅是从镜像仓库中把镜像文件拉取到本地,并不会自动创建容器。

  • 查看所有的容器命令如下:
$ docker ps -a

知道id或者名字就可以用start命令来运行。

关于镜像

Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。

应该说,做镜像文件应该是最难的事情。把自己的东西打包好做成镜像。而且根据这个定义,镜像文件是固定的,如果运行起来需要记录文件等,需要指定到其他的位置(VOLUME卷)。

Docker 官方维护了一个公共仓库 Docker Hub。可以去注册一个账号,注册了可以发布自己的镜像。
通过docker logindocker logout进行登录和退出。

  • 从官方仓库中查找镜像
    想安装一个镜像,得知道都有哪些。执行如下命令,从官方仓库中查找:
$ docker search centos
NAME                               DESCRIPTION                                     STARS               OFFICIAL            AUTOMATED
centos                             The official build of CentOS.                   5672                [OK]                
ansible/centos7-ansible            Ansible on Centos7                              125                                     [OK]
jdeathe/centos-ssh                 OpenSSH / Supervisor / EPEL/IUS/SCL Repos - …   114                                     [OK]
consol/centos-xfce-vnc             Centos container with "headless" VNC session…   100                                     [OK]
centos/mysql-57-centos7            MySQL 5.7 SQL database server                   64                                      
imagine10255/centos6-lnmp-php56    centos6-lnmp-php56                              57                                      [OK]
tutum/centos                       Simple CentOS docker image with SSH access      44                                      
centos/postgresql-96-centos7       PostgreSQL is an advanced Object-Relational …   39                                      
kinogmt/centos-ssh                 CentOS with SSH                                 29                                      [OK]
centos/httpd-24-centos7            Platform for running Apache httpd 2.4 or bui…   26                                      
pivotaldata/centos-gpdb-dev        CentOS image for GPDB development. Tag names…   10                                      
nathonfowlie/centos-jre            Latest CentOS image with the JRE pre-install…   8                                       [OK]
drecom/centos-ruby                 centos ruby                                     6                                       [OK]
centos/tools                       Docker image that has systems administration…   4                                       [OK]
pivotaldata/centos                 Base centos, freshened up a little with a Do…   3                                       
darksheer/centos                   Base Centos Image -- Updated hourly             3                                       [OK]

会有好多好多。看不出来能干嘛。不如直接google

  • 拉取镜像
$ docker pull centos
Pulling repository centos
0b443ba03958: Download complete

前面说过,就是把镜像拉到本地了。

  • 从本地归档文件创建镜像
    已经后的镜像的归档文件在本地了,通过import命令创建镜像。
$ docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]]

参数:

-c :应用docker 指令创建镜像;

-m :提交时的说明文字;

比如:

$ docker import  my_ubuntu_v3.tar runoob/ubuntu:v4  
  • 查看本地镜像
 $ docker image ls

ls后面可以带通配符过滤。或者:

$ docker images
  • 删除本地镜像文件
$ docker image rm [选项] <镜像1> [<镜像2> ...]

可以是镜像的名字,id都可以。或者指定标签REPOSITORY:TAG
可以组合起来按条件删除:

$ docker image rm $(docker image ls -q redis)

ls -q参数表示只显示只显示镜像ID。

  • 删除全部镜像
docker rmi -f $(docker images -a -q)

容器

docker容器是进程级的,启动一个容器,也就是启动了一个进程运行镜像文件的内容。

  • 列出容器
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
575213cf1670        nginx               "nginx -g 'daemon of…"   8 days ago          Up 4 hours          0.0.0.0:80->80/tcp   webserver

这样只显示正在运行的容器。
可以加上参数-a,可以看到已经加载的容器,包括已经运行的和没运行的。

  • 新建并启动
    前面提到,已经拉下来,或者没有拉下来的镜像,都可以直接运行。
$ docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

参数太多了,但好像都有用。直接从runoob.com复制过来参数说明:

-a stdin: 指定标准输入输出内容类型,可选 STDIN/STDOUT/STDERR 三项;

-d: 后台运行容器,并返回容器ID;

-i: 以交互模式运行容器,通常与 -t 同时使用;

-P: 随机端口映射,容器内部端口随机映射到主机的高端口

-p: 指定端口映射,格式为:主机(宿主)端口:容器端口

-t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;

--name="nginx-lb": 为容器指定一个名称;

--dns 8.8.8.8: 指定容器使用的DNS服务器,默认和宿主一致;

--dns-search example.com: 指定容器DNS搜索域名,默认和宿主一致;

-h "mars": 指定容器的hostname;

-e username="ritchie": 设置环境变量;

--env-file=[]: 从指定文件读入环境变量;

--cpuset="0-2" or --cpuset="0,1,2": 绑定容器到指定CPU运行;

-m :设置容器使用内存最大值;

--net="bridge": 指定容器的网络连接类型,支持 bridge/host/none/container: 四种类型;

--link=[]: 添加链接到另一个容器;

--expose=[]: 开放一个端口或一组端口;

--volume , -v: 绑定一个卷

参数不对,一般是启动不了的。
比如我刚刚pull了一个叫httpd的镜像下来,执行:

 $ docker run -d -p 8080:80 --name apache httpd

把容器的80端口映射到宿主机的8080端口,并且起了个名字叫apache,在后台运行。
需要注意的是,再次运行run则会再次创建一个容器,如果名字相同就会创建失败。如果端口相同,我这里是原来启动的容器被停止,新的容器启动了。
如果用create命令,则是只创建,但不运行容器了。

  • 启动/停止/重启容器
$ docker start [OPTIONS] CONTAINER [CONTAINER...]

$ docker stop [OPTIONS] CONTAINER [CONTAINER...]

$ docker restart [OPTIONS] CONTAINER [CONTAINER...]

startrestart有两个参数:

-a 将当前的输入/输出连接到容器
-i 将当前的输入连接到容器上

好像输出都到了宿主机的控制台了。
已经创建好的容器,可以用这三个命令来控制启停。

  • 执行容器命令
    容器启动之后需要控制容器,执行里面的命令,或者进入容器的交互终端,可以使用exec命令:
 $ docker exec [OPTIONS] CONTAINER COMMAND [ARG...]

参数有:

-d :分离模式: 在后台运行

-i :即使没有附加也保持STDIN 打开

-t :分配一个伪终端

it参数往往一起使用。表示打开一个交互终端,比如要进入容器控制台(类似登录到linux服务器的样子)

$ docker exec -it apache bash

就可以执行容器里面的命令,比如ls等。
run命令也可以加入-it参数,但一般作为后台服务来跑,用exec来控制可能更加多用吧。
除了bash命令,可以执行容器里面的其他命令。

  • 查看容器的日志
    后台运行的容器,如果要查看日志:
$ docker logs [OPTIONS] CONTAINER

参数说明:

-f : 跟踪日志输出

--since :显示某个开始时间的所有日志

-t : 显示时间戳

--tail :仅列出最新N条容器日志
  • 查看容器进程
  • 类似linux的top命令一样
$ docker top CONTAINER
  • 删除容器
docker rm [OPTIONS] CONTAINER [CONTAINER...]

可以是容器的id,或者名字。参数:

-f :通过SIGKILL信号强制删除一个运行中的容器
-l :移除容器间的网络连接,而非容器本身
-v :-v 删除与容器关联的卷
  • 删除全部容器
docker rm -vf $(docker ps -a -q)

数据卷

前面提到镜像文件应该是不可变的。一个正式的服务运行起来,会产生很多动态数据,比如数据库记录,日志等,这些信息是很重要的。容器可能可以随便就删掉,轻松创建,但这些数据不能丢。所以提供了数据卷的概念。在宿主机创建一个,用来保存这些重要的业务数据,就算容器删除了,卷的数据也不会消失。

  • 创建一个卷
$ docker volume create my-vol

在本地的/var/lib/docker/volumes下面创建my-vol/_data目录,作为卷的实际保存地方。不过有几个问题:

  1. 这个/var/lib/docker/volumes默认目录,不知道怎么改,如果一定要在这里的话,需要在linux宿主机上专门挂这个目录才行。
  2. create命令对于不同的存储介质有很多参数,docker支持很多存储介质,比如本地磁盘,nfs设置S3,不同的介质需要对应不同的参数,按照docker的说法,这些参数直接传给设备,具体就需要去查了。用--driver指定驱动程序和用-o指定参数。
  3. mac没这个目录!

在linux下没问题,就有这个目录,直接把需要的内容弄进去就好了。
但跑到mac电脑的/var/lib下面根本没有docker目录!docker其实不是直接运行在mac os上,而是在mac os上弄了一个虚拟的linux环境,所以这个/var/lib/docker目录对应的是linux虚拟环境的目录。
执行如下命令进入到linux虚拟环境中:

$ cd ~/Library/Containers/com.docker.docker/Data/vms/0/

$ screen tty

这样出来的终端界面就能找到对应的目录了。进去看看,里面是空的。不知道怎样把mac的内容拷贝进去。
另外,根据文章指出,这个linux虚拟环境退出,需要按住ctrl然后,按a和k。说其他退出方式,会导致有问题。如果有问题,重启docker。
mac目录问题,从[工具][docker]記錄Volume相關引用过来。

比如我要创建了一个叫apache的httpd容器。我打算把真是的网站放在web卷中。先创造卷:

$ docker volume create web

如果是linux就直接把网站内容拷贝到var/lib/docker/volumes/web/_data里面,如果是mac就抓瞎。
然后给容器挂载卷。

  • 挂载卷
$ docker run -d -p 8080:80 --name apache -v webapp:/usr/local/apache2/htdocs httpd

-v参数确定卷名:容器中的的绝对路径。可以先用exec进去看看容器里面对应的网站根目录在哪里。如果是linux,拷贝内容进去就好了。如果是mac,换一种方式,直接指定本机目录挂到容器里面:

$ docker run -d -p 8080:80 --name apache -v /Users/web:/usr/local/apache2/htdocs httpd

把网站内容拷贝到/Users/web目录中就可以。
从 Docker小图标 -> Preferences 进到 File Sharing。可以看到Users目录是共享的。

  • 删除卷
    卷不会被自动删除,需要手工执行:
$ docker volume rm my-vol

进行删除。

  • 查看卷
$ docker volume ls

检查对象信息

使用inspect命令检查对象,比如镜像,容器,卷的信息。

$ docker inspect 对象名字

可以可以到信息。

几个常用镜像包的使用

  • mysql
$ docker run -d -e MYSQL_ROOT_PASSWORD=password -p 53306:3306 --privileged=true --name mysql  docker.io/mysql

--privileged=true表示root在容器内有真正的root权限。
启动镜像, 第一次启动最少需要指定MYSQL_ROOT_PASSWORD
需要修改使用自己的配置文件,可以通过绑定卷实现。
需要登录到容器中修改权限。

  • nginx
$ docker run --name nginx-test -p 8080:80 -d nginx

需要配置:

  • 映射80端口到需要的端口。

  • /etc/nginx/conf 目录或者 /etc/nginx/conf/nginx.conf,nginx配置文件

  • /usr/share/nginx/html 默认的web根目录

  • redis

$ docker run -itd --name redis-test -p 6379:6379 redis

可以看出下载一个现成的docker镜像要用起来的话,有几个条件需要知道:

  • 此镜像需要暴露那些端口,一般标准的比如web服务器,80端口,redis 6379,java中间件如tomcat 8080端口;mysql 3306端口等。一般官方的都会提供默认端口。
  • 了解这个镜像会创建那些卷,虽然创建过程是自动的,但应该知道运行这个镜像会留下那些东西;
  • 那些配置文件是应该放在外面,或者那些目录应该放在外面的。比如,nginx使用默认的配置文件,那么就应该把自己的网站文件的目录映射到/usr/share/nginx/html

官方提供的镜像一般都有详细的说明,hub.docker.com上也会提供Dockerfile,这个都可以先看的。剩下的,就是多尝试了,大不了先把镜像跑起来,用exec进去看看是怎么配置的。

制作镜像文件

从上面的过程来看,docker进行文件的制作才是最重要的。开发好一个服务端应用之后,怎么制作镜像文件,怎么利用docker合理的部署,需要几个镜像,怎么划分等。
制作镜像文件最重要就是编写Dockerfile。

Dockerfile 分为四个部分:

  • 基础镜像(父镜像)信息指令 FROM。
  • 维护者信息指令 MAINTAINER。
  • 镜像操作指令 RUN 、EVN 、ADD 和 WORKDIR 等。
  • 容器启动指令 CMD 、ENTRYPOINT 和 USER 等。

一个最简单的Dockerfile:

#nginx基础镜像
FROM nginx
#指定工作路径
WORKDIR /usr/share/nginx/html
#将前前路径下的所有文件都COPY到工作路径下
COPY . .
#EXPOSE 命令用来指定对外开放的端口,实际用处不大,可不写
EXPOSE 80

Dcokerfile命令如下:

  • FROM
    FROM 是用于指定基础的 images ,一般格式为 FROM 。所有的 Dockerfile 都应该以 FROM 开头,FROM 命令指明 Dockerfile 所创建的镜像文件以什么镜像为基础,FROM 以后的所有指令都会在 FROM 的基础上进行创建镜像。可以在同一个 Dockerfile 中多次使用 FROM 命令用于创建多个镜像。
  • MAINTAINER
    MAINTAINER 是用于指定镜像创建者和联系方式,一般格式为 MAINTAINER xxxxx
  • COPY
    COPY 是用于复制本地主机的(为 Dockerfile 所在目录的相对路径)到容器中的。当使用本地目录为源目录时,推荐使用 COPY 。一般格式为 COPY。例如我们要拷贝当前目录到容器中的 /app 目录下,我们可以这样操作:COPY . /app
  • ADD
    增强版的COPY,支持将远程URL的资源加入到镜像的文件系统。
  • ENV
    指定镜像的环境变量。比如常用的path,JAVA_HOME等。
  • VOLUME
    定义卷。格式为VOLUME ["<路径1>", "<路径2>"...]
  • WORKDIR
    WORKDIR 用于配合 RUN,CMD,ENTRYPOINT 命令设置当前工作路径。可以设置多次,如果是相对路径,则相对前一个 WORKDIR 命令。默认路径为/。一般格式为 WORKDIR /path/to/work/dir
  • RUN
    RUN 用于容器内部执行命令。每个 RUN 命令相当于在原有的镜像基础上添加了一个改动层,原有的镜像不会有变化。一般格式为 RUN。例如我们要安装 Python 依赖包,我们做法如下:RUN pip install -r requirements.txt
  • EXPOSE
    EXPOSE 命令用来指定对外开放的端口。一般格式为 EXPOSE[…]。例如上面那个例子,开放80端口:EXPOSE 80
  • ENTRYPOINT
    ENTRYPOINT 可以让你的容器表现得像一个可执行程序一样。一个 Dockerfile 中只能有一个 ENTRYPOINT,如果有多个,则最后一个生效。
    ENTRYPOINT 命令也有两种格式:
    • ENTRYPOINT ["executable", "param1", "param2"]:推荐使用的 Exec 形式。
    • ENTRYPOINT command param1 param2:Shell 形式。
  • CMD
    CMD 命令用于启动容器时默认执行的命令,CMD 命令可以包含可执行文件,也可以不包含可执行文件。
    不包含可执行文件的情况下就要用 ENTRYPOINT 指定一个,然后 CMD 命令的参数就会作为 ENTRYPOINT 的参数。
    CMD 命令有三种格式:
    • CMD ["executable","param1","param2"]:推荐使用的 exec 形式。
    • CMD ["param1","param2"]:作为ENTRYPOINT的参数。
    • CMD command param1 param2:Shell 形式。
      一个 Dockerfile 中只能有一个 CMD,如果有多个,则最后一个生效。而 CMD 的 Shell 形式默认调用 /bin/sh -c 执行命令。
      CMD 命令会被 Docker 命令行传入的参数覆盖:docker run nginx

感谢Docker系列之四:Dockerfile的使用。从这里参考不少资料。

重点解释几个命令:

  • RUN
    RUN命令其实就是构建这个镜像的时候,基于基础的镜像操作系统执行的一些列命令,让这个环境变成你所要的。比如,基于centos系统,安装java安装数据库等。一般默认的操作系统是debain,使用apt-get安装软件,如果选择centos则使用yum来安装了。
    为了打包快,基本上,第一个干的事情,是更改apt或者yum的源了。
    按照说明,一个RUN命令,形成一个新的镜像,多个RUN就是一层一层的做镜像。如果不想多层镜像,就把所有的指令都在一个RUN里面执行完。命令间用\分割。如:

    apt update -y \
        && apt upgrade \
        && apt install mysql-server -y \
        && apt install redis-server -y 
    
  • ADD和COPY
    两个命令都是把外部的资源复制到镜像中。ADD除了支持把主机的文件,还支持远程URL资源。但ADD不支持认证。一般也不支持用ADD获取远程资源,可以在RUN中用wget获取。
    前面提到更新apt-get的资源,可以:

    $ ADD ./sources.list /etc/apt/
    

    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
    
  • ENV环境变量
    能在构建容器的时候指定的环境变量就在Dockerfile里面指定,毕竟,有些环境变量可能在RUN的时候就会用到。有些比如前面mysql的镜像,root的口令,可以run的时候指定。

  • ENTRYPOINT和CMD
    这两个指令,在构建镜像的时候不会运行,在run的时候执行。相当于镜像启动起来的服务。比如,做一个tomcat的镜像,启动容器的时候自动把tomcat运行起来。
    这两个必须有一个。
    两个命令后面都有带[]和不带中括号的。是所谓的exec模式(带中括号)和shell模式(不带中括号)。推荐是exec模式。区别好像很重要,貌似哪个是1号进程。但我不是很清楚。
    CMD作为默认命令,可以被run的参数覆盖。
    对于 CMD 和 ENTRYPOINT 的设计而言,多数情况下它们应该是单独使用的。当然,有一个例外是 CMD 为 ENTRYPOINT 提供默认的可选参数。

    • 如果 ENTRYPOINT 使用了 shell 模式,CMD 指令会被忽略。
    • 如果 ENTRYPOINT 使用了 exec 模式,CMD 指定的内容被追加为 ENTRYPOINT 指定命令的参数。
    • 如果 ENTRYPOINT 使用了 exec 模式,CMD 也应该使用 exec 模式。

    说了一大堆,其实,一般情况,就用ENTRYPOINT好了。别搞这么复杂。另外,不管CMD还是ENTRYPOINT都只能一个生效,如果写了多个,最后一个生效。如果需要启动多个服务,就写一个脚本,COPY进来,执行就好。
    然而,需要注意的是,启动脚本里面,直接运行命令,而不要用systemctl这样启动服务。如果多个服务,前面的都加&放到后台,最后一个放前台。否则,容器启动完了就退出了。
    比如我的一个启动脚本:

    #!/bin/bash
    mysqld_safe &
    redis-server &   
    sleep 5s
    catalina.sh run
    

    我的tomcat如果在mysql没启动完成就起来了会出错,所以让他睡觉5秒钟。

  • VOLUME
    Dcokerfile里面定义了卷,在运行的时候,如果不显示的指定卷,就会自动创建匿名的卷

如果自己做镜像,可能最麻烦的就是RUN的环节了。可能需要执行很多命令比如:

  • 构建一些目录
  • 设置操作系统的时区,语言
  • 安装各种软件
  • 复制或者ln一些命令
  • 如果安装了数据库可能需要把数据启动起来设置密码和权限再停下来

最好在一个相同的容器里面,每行命令都执行一下,验证通过,同步记录执行的脚本。

最后,构建镜像的命令,在Dcokerfile目录下执行:

$ docker build -t runoob/ubuntu:v1

导出镜像和容器

  • 对镜像文件的操作
    导出镜像文件,文件为tar文件。
$ docker save [镜像名] > [文件名]

导入镜像文件

$ docker load < [文件名]

镜像文件是静态的,不会因为你在对应的容器里面做了什么而改变。一开始制作或者下载的镜像文件是什么样,导出的时候还是什么样。

  • 对容器快照的操作
    容器快照就是运行起来的容器,做了很多操作之后,把当前的快照弄出来变成一个快照文件,这个文件可以恢复成容器。快照文件也是tar文件。
$ docker export [容器id] > [文件名]
$ docker import [文件名]

可以把导入的镜像打标签:

docker tag [镜像id] [镜像名字]:[版本号]

不过,要注意的是,导出来的镜像或者容器快照,都会很大很大。

docker 网络

docker安装好之后,主机会多一个docker0的网卡。用来跟容器通信的。复杂的机制我们不管他,总之,安装之后就有了。而且,运行容器之后,容器本身也会分配一个ip地址。但这个地址,每次重启容器,都可能会改变。想用这个地址来做容器之间通信,是不靠谱的。
所以,就需要专门创建网络。并且把容器都加入到这个网络里面,就可以通过容器的名字来通信了。

创建网络:

$ docker network create congnet

查看这个网络的信息:

$ docker network inspect congnet

可以看出:

"Scope": "local",
"Driver": "bridge",

"Subnet": "172.21.0.0/16",
"Gateway": "172.21.0.1"

docker网络有好几种模式,反正桥接模式就是能访问所有的网络。

创建容器,并加入指定网络:

$ docker run -itd -p 80:80 --name mynginx --net congnet nginx

把已经存在的容器加入到网络:

$ docker network connect congnet [容器id]

这样,容器之间就可以互相用容器的名字通信了。

断开网络:

$ docker network disconnect congnet mynginx

到这里,容器都是在一个主机上的。实际情况,很有可能容器在不同的主机上。这就需要单独的东西。我还没验证。根据资料,用overlay。需要安装consul
暂时不搞他。

docker-compose

下载安装docker-compose

$ sudo curl -L https://github.com/docker/compose/releases/download/1.22.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose

即可完成。

docker-compose使用YAML文件定义多个镜像以及依赖关系。
太复杂了,直接复制一个过来。

#版本号
version: "2.1"
#指定创建的虚拟网络数量 
#作用:通过不同的虚拟网络实现了容器网络之间的隔离,从而在最大程度上去保护后端网络的安全。
#networks:
#mynet:
#driver: bridge
#mynet1:


#重用的代码模板
#模板的定义必须以 x- 开头
x-logging:
	#以 & 开头的字符串为模板命名
	#以 * 加上模板的名称引用模板
  &default-logging
  driver: json-file
  options:
    max-size: "200k"
    max-file: "10"
    
#定义全局挂载卷 
volumes:
  test_1.thinking.com:
  test_2.thinking.com:

#服务
services: 

 #服务名称
 todo:
	# 构建镜像
     build:
     	 # 指定dockerfile的上下文路径(相对当前docker-compose.yml的位置)
     	 #包含Dockerfile文件的目录路径,或者是git仓库的URL。 
     	 #当提供的值是相对路径时,它被解释为相对于当前compose文件的位置。 
     	 #该目录也是发送到Docker守护程序构建镜像的上下文。
       context: . 
       #Dockerfile的文件名称
       dockerfile: Dockerfile-todo
       args:							
       	# 变量
        buildno: 1
        password: secret
       #Dockerfile里面可使用的参数变量			
       #Dockerfile:
       #	ARG buildno 
       #	ARG password
	   #	RUN echo "Build number: $buildno"
	   #	RUN script-requiring-password.sh "$password"
	  
     #镜像名 : 仓库/标签:版本
     image: zhanyang/todo-demo:1.0.0   
       
     #依赖(以指定顺序启动)
     depends_on:  
       mysql:
         condition: service_healthy
         
     #指定一个自定义容器名称,而不是生成的默认名称。
     #由于Docker容器名称必须是唯一的,因此如果指定了自定义名称,则无法将服务扩展到多个容器。
     container_name: todo
     
     #卷挂载路径设置。
     #可以设置宿主机路径 (HOST:CONTAINER) 或加上访问模式 (HOST:CONTAINER:ro)
     #挂载数据卷的默认权限是读写(rw),可以通过ro指定为只读。 
     volumes:
			 	# 只需指定一个路径,让引擎创建一个卷
			  - /var/lib/mysql
			 
			  #指定绝对路径映射
			  - /opt/data:/var/lib/mysql
			 
			  #相对于当前compose文件的相对路径
			  - ./cache:/tmp/cache
			 
			  #用户家目录相对路径
			  - ~/configs:/etc/configs/:ro
			 
			  #命名卷
			  - datavolume:/var/lib/mysql
			  
			  #使用全局挂载卷
			  - test_1.thinking.com:/test:rw
			  
		 #指定日志驱动为 json-file,存储日志的最大文件 size 为 200k,最多存储 10 这样大的文件。
		 #logging支持很多driver,而每一个driver对应的options都不一样
		 #docker inspect -f {{.HostConfig.LogConfig}} lnmp-nginx
		 #result:{json-file map[max-file:10 max-size:2000k]}
		 #docker info |grep 'Logging Driver'
		 #result:Logging Driver: json-file
		 #其他:https://docs.docker.com/engine/admin/logging/overview/
 	logging:
      driver: "json-file"
      options:
        max-size: "200k"
        max-file: "10"
        
		#指定使用的虚拟网络
    networks: 
    #- mynet
    
    #覆盖容器启动后默认执行的命令。 
    #该命令也可以是一个类似于dockerfile的列表:command: ["bundle", "exec", "thin", "-p", "3000"]
    command: bundle exec thin -p 3000
    #may
    command: ["/usr/local/nginx/sbin/nginx"]
	
		# 链接到另一个服务中的容器。 请指定服务名称和链接别名(SERVICE:ALIAS),或者仅指定服务名称。
		# 实际是通过设置/etc/hosts的域名解析,从而实现容器间的通信。
		# 故可以像在应用中使用localhost一样使用服务的别名链接其他容器的服务,前提是多个服务容器在一个网络中可路由联通
		# links也可以起到和depends_on相似的功能,即定义服务之间的依赖关系,从而确定服务启动的顺序
	links:
	   - db
	   - db:database
	   - redis
	   
	  #链接到docker-compose.yml 外部的容器,甚至并非 Compose 管理的容器。参数格式跟 links 类似。
	 external
		 - redis_1
		 - project_db_1:mysql
		 - project_db_1:postgresql
		 
		#暴露端口,但不映射到宿主机,只被连接的服务访问。 仅可以指定内部端口为参数
	 expose:
		 - "3000"
		 - "8000"
		 
		#暴露端口信息。使用宿主:容器 (HOST:CONTAINER)格式或者仅仅指定容器的端口(宿主将会随机选择端口)都可以。
	 ports:
		 - "3000"
		 - "3000-3005"
		 - "8000:8000"
		 - "9090-9091:8080-8081"
		 - "49100:22"
		 - "127.0.0.1:8001:8001"
		 - "127.0.0.1:5000-5010:5000-5010"
		 - "6060:6060/udp"
		#v3.2中ports的长格式的语法允许配置不能用短格式表示的附加字段。
	 ports:
		  - target: 80 #容器内的端口 
		    published: 8080 #物理主机的端口 
		    protocol: tcp #端口协议(tcp或udp) 
		    mode: host #host 和ingress 两总模式,host用于在每个节点上发布主机端口,ingress 用于被负载平衡的swarm模式端口。
		
	#no是默认的重启策略,在任何情况下都不会重启容器。  
	restart: "no"
	#指定为always时,容器总是重新启动。
	restart: always 
	#如果退出代码指示出现故障错误,则on-failure将重新启动容器。
	restart: on-failure
	restart: unless-stopped
	
	  
	#pid 将PID模式设置为主机PID模式。
	#这就打开了容器与主机操作系统之间的共享PID地址空间。 
	#使用此标志启动的容器将能够访问和操作裸机的命名空间中的其他容器,反之亦然。
	#即打开该选项的容器可以相互通过进程 ID 来访问和操作。
	pid: "host"
	
	#配置 DNS 服务器。可以是一个值,也可以是一个列表。
	dns: 8.8.8.8
	dns:
	  - 8.8.8.8
	  - 9.9.9.9
	  
	#自定义搜索域
	dns_search: example.com
	dns_search:
	  - dc1.example.com
	  - dc2.example.com
	  
	#覆盖Dockerfile中的entrypoint,用法同Dockerfile中的用法
	entrypoint: ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]
	
	#添加环境变量。 你可以使用数组或字典两种形式。
	#任何布尔值; true,false,yes,no需要用引号括起来,以确保它们不被YML解析器转换为True或False。 
	environment:
	  RACK_ENV: development
	  SHOW: 'true'
	  SESSION_SECRET:
	#【注意】:如果你的服务指定了build选项,那么在构建过程中通过environment定义的环境变量将不会起作用。
	#将使用build的args子选项来定义构建时的环境变量。

	environment:
	  - RACK_ENV=development
	  - SHOW=true
	  - SESSION_SECRE
	  
	#1>将定义的变量编写在文件中,然后在yml文件中进行添加 
	env_file: .env
	env_file:
	  - ./common.env
	  - ./apps/web.env
	  - /opt/secrets.env
		  
	#2>例如:
	#old:
		db:
	    image: mysql
	    ports:
	      - "3306:3306"
	    environment:
	      MYSQL_ROOT_PASSWORD: redhat
	      MYSQL_DATABASE: wordpress
	      MYSQL_USER: wordpress
	      MYSQL_PASSWORD: wordpress
	      
    #new:
		db:
		   image: mysql
		   ports:
		      - "3306:3306"
		   env_file: ./mysql_env
    
	  #创建env_file文件在当前目录mysql_env
		 MYSQL_ROOT_PASSWORD=redhat
		 MYSQL_DATABASE=wordpress
		 MYSQL_USER=wordpress
		 MYSQL_PASSWORD=wordpress3
		
    #添加hostname映射,类似于docker cli下面的--add-host
	extra_hosts:
     - "www.hcstart.com:192.168.101.14"
 
    #配置一个检查去测试服务中的容器是否运行正常  
    #具体: https://docs.docker.com/engine/reference/builder/#healthcheck
    #查看healthcheck的状态输出 : docker inspect lnmp-nginx
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost"]
      interval: 1m30s
      timeout: 10s
      retries: 3
	
    #labels:添加元数据到container中,查看现有容器的labels:
	#docker inspect -f {{.Config.Labels}} lnmp-nginx # lnmp-nginx :容器名
	labels:
	  com.example.description: "Accounting webapp"
	  com.example.department: "Finance"
	  com.example.label-with-empty-value: ""
	labels:
	  - "com.example.description=Accounting webapp"
	  - "com.example.department=Finance"
	  - "com.example.label-with-empty-value"
	
	#在容器中设置内核参数
    sysctls:
	     net.core.somaxconn: 1024
	     net.ipv4.tcp_syncookies: 0

	sysctls:
	    - net.core.somaxconn=1024
	    - net.ipv4.tcp_syncookies=0
	    
	    
mysql:
     environment:
       MYSQL_ROOT_PASSWORD: password
       MYSQL_DATABASE: tododb
       MYSQL_USER: user
       MYSQL_PASSWORD: pass
     build:
       context: .
       dockerfile: Dockerfile-mysql
     image: zhanyang/mysql:5.6
     container_name: mysql
     #以 * 加上模板的名称引用模板     使用全局自定义模板
     logging: *default-logging
 	 #指定使用的虚拟网络
     networks: 
     #- mynet1

参考:docker-compose.yml参数详解(配置文件)

docker-compose.yml文件目录下执行:

$ docker-compose up -d
发布了20 篇原创文章 · 获赞 7 · 访问量 2493

猜你喜欢

转载自blog.csdn.net/cfy_fantasyxx/article/details/103557072