docker学习笔记(一)
docker是一种容器技术,现在火的一塌糊涂,最近公司打算用docker统一开发、测试、预上线、上线环境,所以花了时间研究一下。
docker是一种容器技术,之前是基于LXC容器,现在已经改成基于libcontainer了。研究了几天,对docker有以下总结:
1)docker是一种容器技术,容器中包含了一个微型操作系统,我们在容器中封装我们要运行的程序环境,这样就节省了环境配置和维护的时间和人力成本,容器有自己的网络环境,可以定制其使用的cpu、内存和磁盘等资源,对于运维来说,尤其是对于频繁发布的运维人员来说,是个福音。据说亚马逊每天要发布上万次、谷歌也有几千次,其发布间隔已经到分钟级。当然这种发布,不仅仅是docker的作用,其他一系列的自动化配置、自动化测试、自动化发布、自动化回滚都要跟上才行。
2)docker的性能要低于裸机,所以在小型系统的运行环境中没有必要使用docker
3)docker的稳定性需要注意,在上线之前需要进行充分的压力测试
4)docker是基于linux的,所以windows和Mac都使用virtualBox虚拟机来实现的。
5)docker可以很快的搭建测试环境,但是对于开发环境来说,因为是另外一台机器,所以调试、自动完成、代码提示都会有一定的问题,需要特殊的配置。
6)docker不是虚拟机,是一个容器,更准确的来说,是一个程序,所以启动容器需要指定启动程序,否则容器会启动失败,另外虽然容器是个微型操作系统,但是没有服务自动运行的概念,这一点对于有一定运维经验的同学来说容易混淆。
7)容器的构建一般基于ubuntu、debian、centos等linux发行版,所以如果想构建自己的docker镜像,最好同时安装对应的虚拟机,测试一些命令,运行成功了,再放到Dockerfile中,否则会比较麻烦。
8)构建容器有两种办法,一种是在现有镜像的基础上,登录容器,更新容器,让后将容器内容保存为镜像,这种方法一般是初学者用来学习测试用,另外一种是常用的Dockerfile,这个文件规定了容器构建的步骤和命令,可以重复运行,并可以根据自己的要求自己修改,得到新的镜像。
9)镜像的获得:最权威的是hub.docker.com,可以在上面搜索到相应的需要的镜像,根据说明文档拉取镜像到本地就可以了,不过速度要慢一些,国内一些公司做了hub.docker.com的备份,可以从国内拉取镜像,速度要快的多,这种公司也不少,daoclound和灵雀云可以尝试一下
10)可以建立自己的私有镜像中心,docker公司提供了一个docker-registry的镜像,可以直接使用,启动之后,就有了一个自己的镜像中心,在上面可以进行发布和拉取镜像的操作,这也算一个快速部署的例子吧,当然也可以在其基础上做定制。
11)docker容器是不会保存文件的,如果容器停止,容器里所作的修改就不存在了,所以容器中需要保存的部分需要放在容器外,可以将宿主机的目录和文件,映射到容器内部,映射之后,如果容器内存在该文件或目录,会覆盖容器内的文件;还可以不指定宿主的目录文件,宿主机会自动生成一个文件,目录文件名是随机的。
12)docker容器本身有自己的ip地址,当docker启动时,默认会创建一个docker0网桥,本机的容器都会从这个网桥得到一个地址,并与之互通,这个地址可以通过docker inspect命令看到,在本机可以直接用ip地址访问。但是其他机器就访问不了了。这个问题的解决方法很多,有的复杂,有的简单,最简单的方法是将容器的对外访问的端口暴露出来,映射到宿主机的端口,这样其他机器就可以访问了。如果容器之间需要访问,因为其ip地址是不确定的,所以需要用容器连接来解决,容器连接本质上是将容器名称和容器IP关联起来,修改父容器的/etc/hosts,所以忽略IP连接问题。当然还有更复杂的,就是不建立docker0网桥,直接分配docker容器地址,配置路由,这个比较麻烦,需要研究一下iptables命令,不过有一些工具可以用来解决这个问题,这也是docker集群大规模部署的基础。感兴趣可以研究一下weave,kubernetes
为方便起见,在linux虚拟机中做docker的实验,环境如下
操作系统:CentOS 7
内存: 3.2G
CPU核数 : 2
实验内容:搭建ngixn 1.9 + php-fpm 5.6 + mysql 5.6
IP:172.16.10.138
步骤如下:
1)安装docker,根据官方网站的步骤
a) 更新软件包
$ yum upate
b) 更新yum资源库
$ tee /etc/yum.repos.d/docker.repo <<-'EOF'
[dockerrepo]
name=Docker Repository
baseurl=https://yum.dockerproject.org/repo/main/centos/$releasever/
enabled=1
gpgcheck=1
gpgkey=https://yum.dockerproject.org/gpg
EOF
c)安装docker
$ yum install docker-engine
$ systemctl start docker
$ systemctl enable docker
需要启动docker服务才可以,否则docker无法使用,上面将docker服务设置为自动启动
d)docker命令简介
docker的启动和运行命令都是docker,docker --help可以看到所有的详细参数内容,常见的有以下内容
docker build 构建镜像,使用Dockerfile
docker run 运行容器
docker pull 拉取镜像
docker push 推送镜像
docker attach 连接到已经运行的容器上
docker restart 重新启动容器
docker rmi 删除镜像
docker rm 删除容器
docker stop 停止容器
docker start 启动容器
docker save 保存镜像到tar文件,包括历史
docker load 恢复tar文件到镜像,save的反命令
docker export 导出镜像最新文件系统到tar文件,没有历史,大小要小于save命令
docker import 导入tar文件生成镜像,export的反命令
docker images 显示所有镜像
docker inspect 显示容器信息
docker ps 显示运行的容器信息
docker ps -l 显示最后的容器信息,即使已经停止
2)配置和目录结构:/root/Dockerfiles下
├── mysql
│ └── Dockerfile
├── nginx
│ ├── default.conf
│ └── Dockerfile
└── php
└── Dockerfile
mysql基本就是从网上下载的镜像,nginx需要修改配置文件,所以增加了一个default.conf,用来覆盖容器内的配置文件,php容器的配置文件比较简单,不做修改
/data/html目录保存html和php文件,保存在容器外,这个目录需要映射到nginx和php容器,也定为/data/html
在/data/html下写入三个文件, index.htm info.php mysql.php,分别测试静态文件、PHP文件、Mysql连接
$ echo '<h1>Hello World!</h1>' > /data/html/index.htm
$ echo '<?php' > /data/html/info.php
$ echo ' phpinfo();' >> /data/html/info.php
$ vim mysql.php
<?php
$con = mysql_connect("mysql", "root", "123456");
if (!$con)
{
die('Could not connect: ' . mysql_error());
}
$db_selected = mysql_select_db("shiyq",$con);
mysql_query("set names utf8");
$sql = "SELECT * from t";
$result = mysql_query($sql,$con);
while($row = mysql_fetch_array($result)){
print_r($row);
}
mysql_close($con);
三个容器命名分别为mysql、pfpm、nginx,便于容器连接
3)mysql, mysql目录下
$vim Dockerfile
FROM mysql:5.6
$docker build -t shiyq/mysql:5.6 .
Sending build context to Docker daemon 2.048 kB
Step 1 : FROM mysql:5.6
5.6: Pulling from library/mysql
7268d8f794c4: Pull complete
a3ed95caeb02: Pull complete
e5a99361f38c: Pull complete
50aeb59ed433: Pull complete
5bedb4177480: Pull complete
366f809ce7dd: Pull complete
9d8799acdbcd: Pull complete
647411343675: Pull complete
a18cdc480897: Pull complete
45d42e99e3be: Pull complete
Digest: sha256:8f7fd54e7253031030d060925e4abb78f8387b7417e3afd4b7fde6551cc50255
Status: Downloaded newer image for mysql:5.6
---> f0e9d0beeb6b
Successfully built f0e9d0beeb6b
mysql:5.6镜像的Dockerfile可以在https://github.com/docker-library/mysql/blob/ace4c65b8e97f0145616386916aabaec518d4e08/5.6/Dockerfile查看
$docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mysql 5.6 f0e9d0beeb6b 26 hours ago 324.2 MB
shiyq/mysql 5.6 f0e9d0beeb6b 26 hours ago 324.2 MB
可以看出有两个镜像,大小是一样的,原因是我创建的镜像其实就是完全的复制官方镜像。
通过Dockerfile可以看出,官方镜像已经用VOLUME指令将mysql数据目录放到了容器外,当容器运行会产生一个随机目录,这个目录可以通过docker inspect看到,不过总是不舒服,这里指定/root/opt/mysql/data来存放数据,即将其映射到/var/lib/mysql,因此,启动容器命令如下
$ docker run -it -e MYSQL_ROOT_PASSWORD=123456 -v /root/opt/mysql/data:/var/lib/mysql shiyq/mysql:5.6
-it代表是交互模式,可以看到输出,主要用于测试,如果正式发布,可以用-d,即后台运行
-e是环境变量,这个容器启动需要设置root密码,这里设置为123456
-v是目录映射,将本地的/root/opt/mysql/data映射为/var/lib/mysql
$docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e5c92a9be37c shiyq/mysql:5.6 "/entrypoint.sh mysql" 4 minutes ago Up 4 minutes 3306/tcp modest_jennings
$ docker inspect e5c92a9be37c
这可以看到很多信息,比如ip地址、环境变量、目录映射等,这里的ip地址是172.17.0.2,在宿主机上运行mysql命令
$ mysql -uroot -p123456 -h 172.17.0.2 -P 3306
就可以登录进去了,和正常的mysql数据库没有区别。
不过这样操作很不方便,需要知道容器的ip地址才能操作,可以将3306端口映射到本地端口,如3307,再次启动容器
$ docker stop e5c92a9be37c
$ docker run -it --name mysql -e MYSQL_ROOT_PASSWORD=123456 -p 3307:3306 -v /root/opt/mysql/data:/var/lib/mysql shiyq/mysql:5.6
$ mysql -uroot -p123456 -h 127.0.0.1 -P 3307
mysql> create database shiyq default character set utf8;
mysql> use shiyq;
mysql> create table t(id int not null auto_increment primary key,name varchar(20),code varchar(20));
mysql> insert into t(name,code) values('石永强','shiyq');
4)php-fpm,php目录下
$ vim Dockerfile
FROM debian:jessie
RUN apt-get update
RUN apt-get install -y php5-fpm php5-mysql php5-mysqlnd
RUN sed -i "s/^listen = .*$/listen = 9000/g" /etc/php5/fpm/pool.d/www.conf
RUN sed -i "s/;daemonize = yes/daemonize = no/g" /etc/php5/fpm/php-fpm.conf
RUN echo "#!/bin/bash" > /root/run.sh
RUN echo "/usr/sbin/php5-fpm" >> /root/run.sh
RUN chmod u+x /root/run.sh
EXPOSE 9000
CMD ["/root/run.sh"]
这个Dockerfile是自定义的,采用了debian 8,同时修改了默认的配置文件,将监听设置从unix socket改为端口9000,并禁止其后台运行。
$ docker build -t shiyq/php-c:5.6-fpm .
$ docker run -it --name pfpm --link mysql -p 9001:9000 -v /data/html:/data/html shiyq/php-c:5.6-fpm
题外话:官方镜像无法使用,不能访问Mysql,所以只好自定义
5)nginx, nginx目录下
$ vim Dockerfile
FROM nginx:1.9
$ docker build -t shiyq/nginx:1.9 .
Sending build context to Docker daemon 2.56 kB
Step 1 : FROM nginx:1.9
1.9: Pulling from library/nginx
7268d8f794c4: Already exists
a3ed95caeb02: Pull complete
455603953088: Pull complete
7648078317e7: Pull complete
Digest: sha256:3feee5ea8dd682950c9873e8c1d9d689b7d257f1ee8f82a11c484cee9dd6c446
Status: Downloaded newer image for nginx:1.9
---> 574907042fd7
Successfully built 574907042fd7
$ docker run -it shiyq/nginx:1.9 /bin/bash
root@1ffba22d4129:/# cat /etc/nginx/conf.d/default.conf
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/log/host.access.log main;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html #
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
将容器的default.conf的内容复制到本地的default.conf,并修改如下
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/log/host.access.log main;
location / {
root /data/html;
index index.html index.htm index.php;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /data/html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
root /data/html;
fastcgi_pass pfpm:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
增加和修改的内容已经黑体标出,主要是修改了默认的目录为/data/html,另外打开了php-fpm,用来运行php程序,不过需要注意的是这里的主机名用的pfpm,这是php-fpm容器使用的名字,最后会采用容器连接的方式连接php-fpm,同样php-fpm也会用同样的方式连接mysql容器。
$ docker run -it --name nginx --link pfpm -p 800:80 -v /data/html:/data/html -v /root/Dockerfiles/nginx/default.conf:/etc/nginx/conf.d/default.conf shiyq/nginx:1.9
6)运行
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e33a1cc68794 shiyq/nginx:1.9 "nginx -g 'daemon off" 2 minutes ago Up 2 minutes 443/tcp, 0.0.0.0:800->80/tcp nginx
40c3ac953494 shiyq/php:5.6-fpm "php-fpm" 4 minutes ago Up 4 minutes 0.0.0.0:9001->9000/tcp pfpm
3228d0f7ce7e shiyq/mysql:5.6 "/entrypoint.sh mysql" 12 minutes ago Up 12 minutes 0.0.0.0:3307->3306/tcp mysql
可以看到启动了3个容器,nginx80端口映射为宿主机800,连接到php容器,php-fpm的9000端口映射为9001端口,连接到mysql容器,mysql容器的3306映射为3307端口
$ curl localhost:800
Hello World!
$ curl localhost:800/mysql.php
Array
(
[0] => 1
[id] => 1
[1] => 石永强
[name] => 石永强
[2] => shiyq
[code] => shiyq
)
7)脚本
$ vim start_npm.sh
docker rm -f $(docker ps -a -q -f name="mysql|pfpm|nginx");
docker run -it -d --name mysql -e MYSQL_ROOT_PASSWORD=123456 -p 3307:3306 -v /root/opt/mysql/data:/var/lib/mysql shiyq/mysql:5.6;
docker run -it -d --name pfpm --link mysql -p 9001:9000 -v /data/html:/data/html shiyq/php-c:5.6-fpm;
docker run -it -d --name nginx --link pfpm -p 800:80 -v /data/html:/data/html -v /root/Dockerfiles/nginx/default.conf:/etc/nginx/conf.d/default.conf shiyq/nginx:1.9;
$./start_npm.sh 可以自动删除容器,并重启容器
8)和windows共享文件
a)建立e:/data/html目录
b)虚拟机共享目录: 虚拟机->控制->设置->共享文件夹,固定分配,选择共享名称为data_html,自动加载和固定分配勾选
c)安装增强功能:虚拟机->设备->安装增强功能,这会在虚拟机上挂载一个硬盘
$ mkdir /mnt/cdrom
$ mount -t auto -r /dev/cdrom /mnt/cdrom
$ yum install bzip2 kernel-devel
$ cd /mnt/cdrom
$ ./VBoxLinuxAdditions.run
d) 挂载到/data/html
$ mount -t vboxsf data_html /data/html
$ curl localhost:800
Array
(
[0] => 1
[id] => 1
[1] => 石永强
[name] => 石永强
[2] => shiyq
[code] => shiyq
)
e)自动挂载
$ chmod +x /etc/rc.local
$ echo 'mount -t vboxsf data_html /data/html' >> /etc/rc.local
f)重启机器,可以看到目录已经挂载,
$ /root/Dockerfiles/start_npm.sh
$ curl localhost:800
Array
(
[0] => 1
[id] => 1
[1] => 石永强
[name] => 石永强
[2] => shiyq
[code] => shiyq
)
Array
(
[0] => 2
[id] => 2
[1] => 刘万斌
[name] => 刘万斌
[2] => liuwb
[code] => liuwb
)
到此就可以和windows共享文件,在windows上开发,在docker中运行,如果用文本编辑器写程序,基本就可以了,但是用ide,就有些麻烦了,需要本机也安装php,要求版本一致,并不容易,尤其是windows上的php很难找到低版本的,不过好在可以在提交测试前就可以发现问题。
未解决的问题
1)网络地址问题:手动配置和工具配置。