# 问题,如何分离mysql和wordpress,使它们每个都单独运行一个容器。
# 解决办法:运行时通过--link选项使它们链接在一起 --link <container_name>:<alias>
>>> docker pull wordpress:latest
>>> docker pull mysql:latest
>>> docker run --name mysqlwp # 起别名
-e MYSQL_ROOT_PASSWORD=root \ # 指定root的密码
-e MYSQL_DATABASE=wordpress \ # 数据库名
-e MYSQL_USER=wordpress \ # 新建数据库用户名
-e MYSQL_PASSWORD=wordpresswd \ 1# 新建数据库用户名密码
-d mysql # 后台启动
>>> docker run --name wordpress --link mysqlwp:mysql -p 80:80 \
-e WORDPRESS_DB_NAME=wordpress \ # wordpress数据库名字
-e WORDPRESS_DB_USER=wordpress \ # wordpress数据库用户名
-e WORDPRESS_DB_PASSWORD=wordpresswd \ # wordpress数据库密码
-d wordpress # 后台运行
## 备份在容器中运行的数据库
### 问题
使用mysql镜像对外提供数据库服务。为了对数据进行持久化,你需要备份该数据库。
### 解决方案
方式1:将宿主机上的卷挂载到MYSQL容器中
方式2:进入MYSQL容器中使用docker exec命令执行mysqldump
# 方式1启动MYSQL镜像时添加挂载目录:
>>> docker run --name mysqlwp # 起别名
-e MYSQL_ROOT_PASSWORD=wordpressdocker \ # 数据库root密码
-e MYSQL_DATABASE=wordpress \ # 数据库名
-e MYSQL_USER=wordpress \ # 新建的数据库用户名
-e MYSQL_PASSWD=wordpresspwd \ # 新建的数据库用户名密码
-v /home/docker/mysql:/var/lib/mysql \ # 数据卷挂载
-d mysql # 后台运行
# 方式2 直接进入到容器中然后导出数据库数据
>>> docker exec mysqlwp mysqldump --all-databases \
--password=wordpressdocker > wordpress.backup
## docker自动管理并创建卷,即挂载时不指定宿主机的路径
>>> docker run -it -v /cookbook ubuntu:18.04 /bin/bash
>>> root@b12345678:/# touch /cookbook/foobar
>>> root@b12345678:/# ls cookbook/ # foobar
>>> root@b12345678:/# exit
>>> docker inspect -f {{.Mounts}} b12345678 # 查看宿主机上数据集挂载的目录,如/var/lib/docker/volumes/3fc42c8b6e88b2244332fdc85013f5ef72f0185e35ebd69ebf9b50cffb15fcb4/_data
>>> ls /var/lib/docker/volumes/3fc42c8b6e88b2244332fdc85013f5ef72f0185e35ebd69ebf9b50cffb15fcb4/_data # foobar
## 将容器中的卷共享给其它容器,--volumes-from
## 重新创建一个数据容器,然后在创建另一个容器来挂载源数据容器*享的卷。
>>> docker run -v /data --name data ubuntu:18.04
>>> docker inspect -f {{.Mounts}} data # /var/lib/docker/volumes/4e2te4d288sj299sff
>>> docker rm -v data # 删除容器和它的卷
>>> docker run -it --volumes-from data ubuntu:18.04 /bin/bash # 复制上面容器*享的卷
>>> touch /data/foobar # 在此容器中测试创建文件夹
>>> ls /var/lib/docker/volumes/4e2te4d288sj299sff # 查看宿主机上挂载的共享卷是否也有刚才创建的文件夹
## 对容器进行数据复制 docker cp
### 将容器中的文件复制到宿主机上的当前位置
>>> docker cp testcopy:/root/file.txt .
### 将文件从宿主机复制到容器中
>>> docker cp host.txt testcopy:/root/host.txt
### 实用场景,将一个容器中的文件复制到另一个容器中,可以将宿主机作为中转站,进行两次cp即可
>>> docker cp c1:/root/file.txt . # 先将c1容器中的file.txt拷贝到当前宿主机路径上
>>> docker cp file.txt c2:/root/file.txt # 将宿主机上的文件拷贝到c2容器上的
## 将对容器的修改提交到镜像 docker commit
### 问题:在容器内部进行一些修改之后,你想将这些修改保存下来,你不想在退出或者停止这个容器后丢失这些修改,并且你还想将这些修改作为其它容器的基础进行重用。
### 解决:使用docker commit来将一个修改的容器提交为一个新的镜像
>>> docker run -it ubuntu:18.04 /bin/bash
>>> apt-get update # 进入容器后更新apt-get
>>> exit
>>> docker commit 79822dd11d1 ubuntu:update # 将上面的容器提交为一个新的镜像
>>> docker rm 79822dd11d1 # 将原来的这个容器删除
>>> docker run -it ubuntu:update # 运行这个镜像启动新容器
## 如何查看在容器中对镜像作出的修改 docker diffsss
>>> docker diff 79822dd11d1
A /root/.bash_history
D /var/cache/apt/pkgcache.bin
C /var/lib
A表示文件或者文件夹是新增的,C表示文件内容有修改,D则表示该项目已经删除
## 将镜像保存为tar文件进行共享 save和load
>>> docker save -o update1.tar update # 保存镜像
>>> docker rmi update # 删除镜像
>>> docker load < update1.tar # 加载镜像
## 将flask应用打包到镜像
>>> vim Dockerfile
FROM ubuntu:18.04
RUN apt-get update && \
apt-get install -y pyton3 pyton3-pip && \
apt-get clean all && \
pip3 install flask
COPY hello.py /tmp/hello.py
EXPOSE 5000
CMD ["python3", "/tmp/hello.py"]
>>> docker build -t flask . # 构建镜像
>>> docker images # 查看
>>> docker run -d -P flask # -d 后台运行 -P 生成随机端口并映射到dockerfile中暴露的5000端口
## 通过标签对镜像进行版本管理 docker tag
### 问题:当创建了多个镜像以及同一个镜像的多个版本。你希望通过采取某种方式来对镜像和镜像的版本进行跟踪,而不是使用镜像ID。
### 解决办法:通过docker tag为镜像打标签。允许对已有镜像进行重命名,或者为同一个镜像名创建新的标签。
>>> docker images
ubuntu 18.04
>>> docker tag ubuntu:18.04 foobar # 不指定新镜像的标签则默认会使用latest
>>> docker images
foobar latest
ubuntu 18.04
>>> docker tag ubuntu:18.04 foobar:cookbook # 指定新镜像的标签
foobar cookbook
foobar latest
ubuntu latest
## onbuild指令,为他人做嫁衣
### 问题:有时候可以看到有些Dockerfile文件中有一行类型FROM golang:1.3-onbuild的内容,这种镜像的工作原理
### 解决:onbuild指令定义了一个会在未来执行的触发器。这个触发器是一个常规Dockerfile指令,比如RUN或ADD。包含onbuild指令的镜像我们称之为父镜像。当一个父镜像被用作基础镜像时(即通过FROM指令被引用),新镜像也被称为子镜像,子镜像构建过程中会触发在父镜像onbuild中定义的指令
### 示例
>>> vi Dockerfile # 父镜像
FROM node:0.12.6
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
ONBUILD COPY package.json /usr/src/app/
ONBUILD RUN npm install
ONBUILD COPY . /usr/src/app
CMD ["npm", "start"]
>>> docker build -f Dockerfile -t node:0.12.6-onbuild .
>>> vi Dockerfile # 基于父镜像构建的子镜像
FROM node:0.12.6-onbuild # 会执行父镜像中的定义的ONBUILD指令
>>> docker build -f Dockerfile -t node_son:0.12.6-onbuild .
## 自动化构建
https://docs.docker.com/docker-hub/builds/
## 查看容器的IP地址
>>> docker run -d --name nginx nginx
>>> docker inspect --format '{{ .NetworkSettings.IPAddress }}' nginx
## 将容器端口暴露到主机上
### 启动容器时可以指定-P,会随机生成一个端口映射到容器内的程序端口。 -p 指定一个端口映射到容器内的程序端口。 如果当你在Dockerfile文件中添加EXPOSE,则docker run启动容器的时候添加-P时就不需要指定容器内的端口
## 在docker中进行容器链接
>>> docker run -d --name database -e MYSQL_ROOT_PASSWORD=root mysql
>>> docker run -d --link database:db --name web runse/hostname
>>> docker run -d --link web:application --name lb nginx
将容器链接起来之后,在web应用容器中会包含一些指向数据库的环境变量。类似的,在负载均衡容器中,也存在指向web应用容器的环境变量,如:
>>> docker exec -it web env | grep DB
>>> docker exec -it lb env | grep APPLICATION
可以用这些环境变量来动态配置应用程序和负载均衡
/etc/hosts文件也会自动更新,该文件包含了最新的名称解析相关信息。
>>> docker exec -it lb cat /etc/hosts
## 查看正在运行的容器中都使用了哪些容器链接
>>> docker inspect -f "{{.HostConfig.Links}}" application
## 理解docker容器网络
在默认安装情况下,Docker会在宿主机上创建一个名为docker0的linux网桥设备。该网桥设备拥有一个私有网络地址及其所属子网。分配给docker0网桥的子网地址为172.[17-31].41.1/16、10.[0-255].42.1/16和192.168.[42-44].1/24中第一个没有被占用的子网地址。因此,很多时候你的docker0网桥设备的地址都是172.17.42.1。所有容器都会连接到该网桥设备上,并从中分配一个位于子网172.17.42.0/24中的ip地址。容器连接到网桥的网络接口会把docker0网络设备作为网关。创建新容器时,docker会创建一对网络设备接口,并将它们放到两个独立的网络命名空间:一个网络设备放到容器的网络命名空间(即eth0);另一个网络设备放到宿主机的网络命名空间,并连接到docker0网桥设备上。
## 容器网络模式--net
>>> docker run -it --rm --net=none ubuntu:18.04 bash # 启动一个不带任何网络功能的容器
>>> docker run -it --rm --net=host ubuntu:18.04 bash # 启动一个host模式的容器
## 上面两个模式都不推荐,推荐下面
可以选择的容器网络模式是与已经启动的容器共享一个网络命名空间,我们启动一个容器并将其主机名设置为cookbook
>>> docker run -it --rm -h cookbook ubuntu:18.04 bash
>>> ifconfig # 可以看到这个容器被连接到了docker0网桥设备上
我们再启动第二个容器,该容器将使用第一个容器的网络命名空间。启动命令--net=container:CONTAINER_NAME_OR_ID
>>> docker run -it --rm --net=container:cocky_galileo ubuntu:18.04 bash
新的容器具有与第一个启动的容器相同的主机名,当然也具有相同的IP。再每个容器中的进程将是隔离的,存在于自己的进程命名空间中,但是它们共享同一网络命名空间,并可以通过环回设备进行通信。
## 配置docker守护进程iptables和ip转发设置
### 问题:docker默认启用ip转发功能并且修改你的iptables规则表
### 解决方案:在启动docker守护进程时通过--ip-forward=false和--iptables=false参数对docker的网络进行定制
>>> systemctl stop docker # 先停止docker守护进程
>>> echo DOCKER_OPTS=\"--iptables=false --ip-forward=false\" >> /etc/default/docker
>>> iptables -t nat -D POSTROUTING 1
>>> echo 0 > /proc/sys/net # 将ip转发标志设置为0
>>> systemctl restart docker
上述配置,经过docker网桥docker0的通信流量都不会被转发到容器的网络接口上,也不会添加postrouting和masquerading规则。这意味着所有来自容器对外部的网络访问请求都会被丢弃。
如何手动恢复容器对外部网络的访问?
>>> echo 1 >/proc/sys/net/ipv4/ip_forward
>>> iptables -t nat -A POSTROUTING -s 172.17.0.0/16 -j MASQUERADE
## 远程仓库镜像规范
[REGISTRYHOST/][USERNAME/]NAME[:TAG] # 仓库主机/用户名/容器短名:标签
quay.io/dockerinaction/ch3_hello_registry:
# 同时删除正在运行的容器及卷
docker rm -v as3466dhcb
# 删除所有停止的容器和卷
docker rm -v $(docker ps -aq)
## docker中4中网络模式的介绍
--net closed # 只能本地程序进程通信,不能访问外网
--net bridge # 可以访问外部网络
--hostname barker # 自定义命名解析,会将提供的主机名映射成该容器的桥接IP地址到/etc/hosts
--dns 8.8.8.8 # 指明容器运行时需要的dns服务器
--add-host test:10.10.10.255 # 自定义从主机名到ip地址的映射关系到/etc/hosts