Docker容器学习梳理--应用程序容器环境部署

时间:2022-04-23
本文章向大家介绍Docker容器学习梳理--应用程序容器环境部署,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

关于国内Docker镜像,可以参考:Docker容器学习梳理--基础知识(2) 的Docker镜像使用。

如果我们需要在Docker环境下部署tomcat、redis、mysql、nginx、php等应用服务环境,有下面三种方法:

1)根据系统镜像创建Docker容器,这时容器就相当于是一个虚拟机,进入容器内部署应用环境。
   然后将这种应用容器提交为新的镜像,最后基于这种新的应用镜像创建容器,创建时做好端口映射,就可以在外部访问这些应用了。
2)直接通过docker pull拉取别人提交好的tomcat、nginx等应用程序镜像,然后基于这些镜像去创建容器。
3)通过dockerfile制作自己的应用程序镜像。

根据系统镜像部署应用容器,简单做法如下:
1)启动centos系统镜像的容器my_container
2)在my_container容器里部署例如nginx、php、mysql、php的服务
3)将部署完对应服务的容器my_container提交为新的镜像
4)然后根据新镜像去创建容器
5)这个新镜像可以打包,导入到别的Docker服务器上使用

启动容器时,记得要做好端口映射和目录映射。端口映射是为了实现在外部能成功访问到容器里的应用服务。目录映射是为了实现宿主机和容器的数据共享,这样要对容器做修改时,直接在宿主机的映射目录下做修改就行。修改数据的操作最好不要在容器内进行;原则上来说一个应用启动一个容器,最好别在一个容器内启动多个应用。

下面列举几个通过应用服务镜像部署环境的例子: Docker宿主机内网ip:192.168.1.23 Docker宿主机外网ip:103.110.186.23 Docker部分命令解释:

-i:表示以“交互模式”运行容器
-t:表示容器启动后会进入其命令行。加入这两个参数后,容器创建就能登录进去。即分配一个伪终端。
--name :表示创建的容器名为my-nginx
-v:表示目录映射关系(前者是宿主机目录,后者是映射到宿主机上的目录),可以使用多个-v做多个目录或文件映射。
    注意:最好做目录映射,在宿主机上做修改,然后共享到容器上。
-d:在run后面加上-d参数,则会创建一个守护式容器在后台运行(这样创建容器后不会自动登录容器,如果只加-i -t两个参数,创建后就会自动进去容器)。docker attch登录容器时如果卡着,按ctrl+c。
-p:表示端口映射,前者是宿主机端口,后者是容器内的映射端口。可以使用多个-p做多个端口映射

如果创建容器时报如下错:

docker: Error response from daemon: failed to create endpoint mosredis on network bridge: iptables failed: iptables --wait -t filter -A DOCKER ! -i docker0 -o docker0 -p tcp -d 172.17.0.6  -j ACCEPT: iptables: No chain/target/match by that name.
 (exit status 1).

解决办法:
一般来说,重启docker服务,即可解决这个问题。
[root@localhost ~]# systemctl restart docker
[root@localhost ~]# 
----------------------------------
如果重启docker服务解决不了,那么如下操作:
[root@localhost ~]# pkill docker
[root@localhost ~]# iptables -t nat -F
[root@localhost ~]# ifconfig docker0 down
[root@localhost ~]# brctl delbr docker0

一、redis容器环境部署

拉取redis镜像(这里拉取的是官方镜像。也可以自己制作redis镜像)
[root@localhost ~]# docker pull redis
[root@localhost ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
docker.io/redis     latest              e4a35914679d        2 weeks ago         182.9 MB
 
用下面的命令启动Redis容器,记得要带上“-d”参数.在run后面加上-d参数,则会创建一个守护式容器在后台运行。 
[root@localhost ~]# docker run --name myredis -d docker.io/redis
7a273a550005b8494be9d48970a6cc4efbaddd8a152261310a07237d43c9eb16

[root@localhost ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
7a273a550005        docker.io/redis     "docker-entrypoint.sh"   3 seconds ago       Up 2 seconds        6379/tcp            myredis
 
连接容器的redis
1)第一种方式:找出容器的ip
[root@localhost ~]# docker inspect --format='{{.NetworkSettings.IPAddress}}' 7a273a550005
172.17.0.2
 
然后连接容器的redis
[root@localhost ~]# redis-cli -h 172.17.0.2 -p 6379
redis 172.17.0.2:6379> ping      //验证下redis服务是否已经连接上
PONG
redis 172.17.0.2:6379>

2)第二种方式:
[root@localhost ~]# docker run --name myredis -d docker.io/redis
5e260566925e9d6a31b47a47124feb10f3dcfce131c6aa67647881da7874502b
    
[root@localhost ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
5e260566925e        docker.io/redis     "docker-entrypoint.sh"   13 minutes ago      Up 13 minutes       6379/tcp            myredis
    
下面的命令表示新建一个容器(命名为myredis2),将redis-cli运行在里面。然后使用--link将这个容器和之前的redis容器(myredis)连接起来,并将其别名命名为redisdb。
Docker会在redis容器中的/etc/hosts路径下为"redisdb"创建一个入口,并指向redis容器的IP地址.
这样在这两个容器里就可以使用“redisdb”来作为提供redis容器的机器名,也就可以利用这个别名来连接容器redis。
[root@localhost ~]# docker run --rm -it --name myredis2 --link myredis:redisdb docker.io/redis /bin/bash
root@4d4b25678b84:/data# redis-cli -h redisdb -p 6379
redisdb:6379> ping
PONG
redisdb:6379>
    
-----------------------------------------------------
当然,这样也可以如上面先查容器ip进行连接
[root@localhost ~]# docker inspect --format='{{.NetworkSettings.IPAddress}}' 5e260566925e
172.17.0.2
[root@localhost ~]# redis-cli -h 172.17.0.2 -p 6379
redis 172.17.0.2:6379>

3)第三种方式:通过端口映射,外部连接redis容器应用的方法
创建Redis容器实例,这里使用了Docker的端口映射机制,从而就可以使用Host服务器的IP访问这些redis实例.
如下创建三个redis容器实例
[root@localhost ~]# docker run -d --name node1 -p 7001:6379 docker.io/redis
e4b8ca12d9e76441efe2074ab1109757a33a45aff71d1a553140d48d88133372
[root@localhost ~]# docker run -d --name node2 -p 7002:6379 docker.io/redis
a8ee6f48f431651a0342fba289604046cd5b142f53a7eb43f655dde397a06a6f
[root@localhost ~]# docker run -d --name node3 -p 7003:6379 docker.io/redis
2b61bf6765a8c254df9dd41d3ece6b12f4dd768976e6e22f327516063fc2e634
[root@localhost ~]#
 
[root@localhost ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS                    NAMES
2b61bf6765a8        docker.io/redis     "docker-entrypoint.sh"   48 seconds ago       Up 47 seconds       0.0.0.0:7003->6379/tcp   node3
a8ee6f48f431        docker.io/redis     "docker-entrypoint.sh"   55 seconds ago       Up 55 seconds       0.0.0.0:7002->6379/tcp   node2
e4b8ca12d9e7        docker.io/redis     "docker-entrypoint.sh"   About a minute ago   Up About a minute   0.0.0.0:7001->6379/tcp   node1
 
在容器之间建立连接
可以创建应用程序容器,使用--link参数来创建一个连接redis容器,使用别名,将会在redis容器和redis实例容器中创建一个安全的通信隧道
 
------------node1操作------------
[root@localhost ~]# docker run --link node1:db -i -t docker.io/redis /bin/bash
root@8fd8d9db3cc1:/data#
 
现在可以测试连接,首先要先查看下web应用程序容器的环境变量,可以用我们的ip和端口来连接redis容器
root@8fd8d9db3cc1:/data# env | grep DB_
DB_PORT_6379_TCP_PORT=6379
DB_NAME=/nauseous_heisenberg/db
DB_PORT=tcp://172.17.0.2:6379
DB_PORT_6379_TCP=tcp://172.17.0.2:6379
DB_ENV_GOSU_VERSION=1.7
DB_ENV_REDIS_DOWNLOAD_URL=http://download.redis.io/releases/redis-3.2.8.tar.gz
DB_ENV_REDIS_VERSION=3.2.8
DB_PORT_6379_TCP_ADDR=172.17.0.2
DB_PORT_6379_TCP_PROTO=tcp
DB_ENV_REDIS_DOWNLOAD_SHA1=6780d1abb66f33a97aad0edbe020403d0a15b67f
 
可以看到上面命令结果中有一个DB为前缀的环境变量列表,DB来自指定别名连接对应的应用容器,这里就可以使用DB_PORT_6379_TCP_ADDR变量连接到Redis容器。
root@8fd8d9db3cc1:/data# redis-cli -h $DB_PORT_6379_TCP_ADDR
172.17.0.2:6379> ping
PONG
172.17.0.2:6379> set node1 redis-node1
OK
172.17.0.2:6379> get node1
"redis-node1"
172.17.0.2:6379>
 
------------node2操作------------
[root@localhost ~]# docker run --link node2:db2 -i -t docker.io/redis /bin/bash
root@8eb2ccc2aff3:/data# env | grep DB2_
DB2_PORT_6379_TCP_PROTO=tcp
DB2_ENV_REDIS_DOWNLOAD_URL=http://download.redis.io/releases/redis-3.2.8.tar.gz
DB2_PORT_6379_TCP_ADDR=172.17.0.3
DB2_ENV_GOSU_VERSION=1.7
DB2_PORT=tcp://172.17.0.3:6379
DB2_PORT_6379_TCP_PORT=6379
DB2_ENV_REDIS_VERSION=3.2.8
DB2_ENV_REDIS_DOWNLOAD_SHA1=6780d1abb66f33a97aad0edbe020403d0a15b67f
DB2_PORT_6379_TCP=tcp://172.17.0.3:6379
DB2_NAME=/furious_kare/db2
 
root@8eb2ccc2aff3:/data# redis-cli -h $DB2_PORT_6379_TCP_ADDR
172.17.0.3:6379> ping
PONG
172.17.0.3:6379> set node2 redis-node2
OK
172.17.0.3:6379> get node2
"redis-node2"
172.17.0.3:6379>
 
------------node3操作------------
[root@localhost ~]# docker run --link node3:db3 -i -t docker.io/redis /bin/bash
root@d60d074ca66b:/data# env|grep DB3_
DB3_PORT_6379_TCP_ADDR=172.17.0.4
DB3_PORT_6379_TCP_PORT=6379
DB3_PORT_6379_TCP_PROTO=tcp
DB3_ENV_REDIS_DOWNLOAD_SHA1=6780d1abb66f33a97aad0edbe020403d0a15b67f
DB3_NAME=/amazing_kalam/db3
DB3_PORT=tcp://172.17.0.4:6379
DB3_ENV_REDIS_VERSION=3.2.8
DB3_ENV_GOSU_VERSION=1.7
DB3_ENV_REDIS_DOWNLOAD_URL=http://download.redis.io/releases/redis-3.2.8.tar.gz
DB3_PORT_6379_TCP=tcp://172.17.0.4:6379
 
root@d60d074ca66b:/data# redis-cli -h $DB3_PORT_6379_TCP_ADDR
172.17.0.4:6379> ping
PONG
172.17.0.4:6379> set node3 redis-node3
OK
172.17.0.4:6379> get node3
"redis-node3"
172.17.0.4:6379>
 
这样就可以在docker宿主机或其他服务器上通过宿主机的ip地址以及映射的端口进行连接
[root@localhost ~]# redis-cli -h 192.168.1.23 -p 7001
redis 192.168.1.23:7001> get node1
"redis-node1"
redis 192.168.1.23:7001>
 
[root@localhost ~]# redis-cli -h 192.168.1.23 -p 7002
redis 192.168.1.23:7002> get node2
"redis-node2"
redis 192.168.1.23:7002>
 
[root@localhost ~]# redis-cli -h 192.168.1.23 -p 7003
redis 192.168.1.23:7003> get node3
"redis-node3"
redis 192.168.1.23:7003>

注意一个细节: 创建应用容器的时候,一般会做端口映射,这样是为了让外部能够访问这些容器里的应用。可以通过-P或-p参数来指定端口映射

1)当使用-p标记时,可以指定端口映射,即容器端口映射到宿主机的对应端口。可以用多个-p指定多个端口映射关系。如下:
[root@localhost ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
docker.io/redis     latest              e4a35914679d        2 weeks ago         182.9 MB

[root@localhost ~]# docker run --name myredis -p 63799:6379 -d docker.io/redis
f5d5ff51ace01c5f26fcd65a6ca4853f8556a333c812576123ed71fd3d405737

[root@localhost ~]# docker ps 
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                     NAMES
f5d5ff51ace0        docker.io/redis     "docker-entrypoint.sh"   6 seconds ago       Up 5 seconds        0.0.0.0:63799->6379/tcp   myredis

[root@localhost ~]# docker run --rm -it --name myredis2 --link myredis:redisdb docker.io/redis /bin/bash
root@16b660ff9f65:/data# redis-cli -h redisdb -p 6379
redisdb:6379> ping
PONG
redisdb:6379> set test linux
OK
redisdb:6379>

在别的机器上通过访问本机的63799端口连接这个容器的redis
[root@linux-node2 ~]# redis-cli -h 192.168.1.23 -p 63799
192.168.1.23:63799> get test
"linux"
192.168.1.23:63799> 


2)当使用-P标记时,Docker 会随机映射一个 49000~49900 的端口到内部容器开放的网络端口。如下:
[root@localhost ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
docker.io/redis     latest              e4a35914679d        2 weeks ago         182.9 MB

[root@localhost ~]# docker run --name myredis -P -d docker.io/redis
805d0e21e531885aad61d3e82395210b50621f1991ec4b7f9a0e25c815cc0272

[root@localhost ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                     NAMES
805d0e21e531        docker.io/redis     "docker-entrypoint.sh"   4 seconds ago       Up 3 seconds        0.0.0.0:32768->6379/tcp   myredis

从上面的结果中可以看出,本地主机的32768端口被映射到了redis容器的6379端口上,也就是说访问本机的32768端口即可访问容器内redis端口。

测试看下,登陆redis容器,随意写个数据
[root@localhost ~]# docker run --rm -it --name myredis2 --link myredis:redisdb docker.io/redis /bin/bash
root@be44d955d6f4:/data# redis-cli -h redisdb -p 6379
redisdb:6379> set wangshibo huanqiu
OK
redisdb:6379> 

在别的机器上通过上面映射的端口32768连接这个容器的redis
[root@linux-node2 ~]# redis-cli -h 192.168.1.23 -p 32768
192.168.1.23:32768> get wangshibo
"huanqiu"

二、nginx容器环境部署(下面是自己制作的应用镜像)

[root@linux-node2 ~]# docker images
REPOSITORY                   TAG                 IMAGE ID            CREATED             SIZE
centos                       latest              67591570dd29        3 months ago        191.8 MB

为了防止centos7镜像容器里出现:Failed to get D-Bus connection: Operation not permitted 这个bug错误,需要在启动容器的时候添加--privileged参数
并且后面登录容器执行的命令是/sbin/init,如下:
[root@linux-node2 ~]# docker run --privileged -t -i centos /sbin/init

上面命令执行后,会一直卡着。这个不要紧,再打开一个终端窗口,查看并登录容器:
[root@linux-node2 ~]# docker ps
CONTAINER ID    IMAGE       COMMAND        CREATED          STATUS         PORTS  NAMES
eaf66f1e43ab    centos      "/sbin/init"   16 seconds ago   Up 15 seconds         hungry_khorana

[root@linux-node2 ~]# docker exec -it eaf66f1e43ab /bin/bash
[root@eaf66f1e43ab /]#

接着在容器里安装nginx
[root@eaf66f1e43ab /]# yum install -y wget lsof vim

添加CentOS 7 Nginx yum资源库,然后安装nginx
[root@eaf66f1e43ab /]# rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
[root@eaf66f1e43ab /]# yum install -y nginx

[root@eaf66f1e43ab conf.d]# pwd 
/etc/nginx/conf.d
[root@eaf66f1e43ab conf.d]# cat test.conf 
server {
listen 8080;
server_name localhost;
location / {
root /var/www/html;
index index.html;
}
}

[root@eaf66f1e43ab conf.d]# mkdir -p /var/www/html
[root@eaf66f1e43ab conf.d]# cat /var/www/html/test.html
this is nginx page of docker!!

[root@eaf66f1e43ab conf.d]# systemctl start nginx.service

将这个容器提交为新的镜像
[root@linux-node2 ~]# docker stop eaf66f1e43ab
[root@linux-node2 ~]# docker commit eaf66f1e43ab my-nginx
[root@linux-node2 ~]# docker images
REPOSITORY                   TAG                 IMAGE ID            CREATED             SIZE
my-nginx                     latest              8dacda904e00        45 minutes ago      314.4 MB

将上面提交的镜像打包
[root@linux-node2 ~]# docker save my-nginx > /root/my-nginx.tar.gz

然后将这个镜像包上传到别的机器上,比如上传到192.168.1.23机器上的/root下。
在192.168.1.23机器上导入新镜像
[root@localhost ~]# docker load < /root/my-nginx.tar.gz
[root@localhost ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
my-nginx            latest              8dacda904e00        50 minutes ago      314.4 MB

启动nginx容器
[root@localhost ~]# docker run -t -i --privileged --name nginx -v /var/www/html:/var/www/html -p 8899:8080 my-nginx /sbin/init

上面命令执行后会卡着,在另一个端口窗口:
[root@localhost ~]# docker ps 
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                    NAMES
3b5cbea50052        my-nginx            "/sbin/init"        36 seconds ago      Up 35 seconds       0.0.0.0:8899->8080/tcp   nginx
[root@localhost ~]# docker exec -t -i 3b5cbea50052 /bin/bash 
[root@3b5cbea50052 /]# 

[root@3b5cbea50052 /]# systemctl start nginx.service
[root@3b5cbea50052 /]# ps -ef|grep nginx
root       117     1  0 16:47 ?        00:00:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
nginx      118   117  0 16:47 ?        00:00:00 nginx: worker process
root       120    88  0 16:47 ?        00:00:00 grep --color=auto nginx
[root@3b5cbea50052 /]# cat /etc/nginx/conf.d/test.conf 
server {
listen 8080;
server_name localhost;
location / {
root /var/www/html;
index index.html;
}
}

[root@3b5cbea50052 /]# cat /etc/nginx/conf.d/test.conf 
server {
listen 8080;
server_name localhost;
location / {
root /var/www/html;
index index.html;
}
}

[root@localhost ~]# cat /var/www/html/index.html
this is page of Docker-nginx-test!!!

Docker宿主机的iptables防火墙设置好映射端口8899

测试访问

---------------------------------------------------------------------------- 根据nginx应用镜像直接创建:

[root@localhost ~]# docker pull nginx
[root@localhost ~]# docker images
docker.io/nginx                latest              5e69fe4b3c31        4 days ago          182.5 MB

[root@localhost ~]# docker run -ti -d --name my-nginx -p 9988:80 docker.io/nginx /bin/bash
55ae1f2b1eca6638e11865171f322a55cfa277a0aec06526428a1887229b022e
[root@localhost ~]# docker ps
CONTAINER ID        IMAGE                       COMMAND             CREATED             STATUS              PORTS                           NAMES
55ae1f2b1eca        docker.io/nginx             "/bin/bash"         3 seconds ago       Up 3 seconds        443/tcp, 0.0.0.0:9988->80/tcp   my-nginx

[root@localhost ~]# docker exec -ti my-nginx /bin/bash
root@55ae1f2b1eca:/# find / -name nginx
/etc/default/nginx
/etc/init.d/nginx
/etc/logrotate.d/nginx
/etc/nginx
/usr/lib/x86_64-linux-gnu/perl5/5.20/auto/nginx
/usr/lib/nginx
/usr/sbin/nginx
/usr/share/doc/nginx
/usr/share/lintian/overrides/nginx
/usr/share/nginx
/var/cache/nginx
/var/log/nginx

root@55ae1f2b1eca:/# mkdir -p /var/web/www
root@55ae1f2b1eca:/# exit
exit

[root@localhost ~]# docker cp my-nginx:/etc/nginx /var/
[root@localhost ~]# mkdir -p /var/web/www
[root@localhost ~]# cd /var/web/www/
[root@localhost www]# echo "12313123" > index.html

[root@localhost ~]# docker stop my-nginx
my-nginx
[root@localhost ~]# docker rm my-nginx
my-nginx
[root@localhost ~]# docker run -ti -d --name my-nginx -v /var/nginx:/etc/nginx -v /var/web/www:/var/web/www -p 8899:80 docker.io/nginx /bin/bash
af8a4594d643197d204200cd1e3b6a3d000cae71ef92826c0e40edfa87026a2a
[root@localhost ~]# docker ps
CONTAINER ID        IMAGE                       COMMAND             CREATED             STATUS              PORTS                           NAMES
af8a4594d643        docker.io/nginx             "/bin/bash"         52 seconds ago      Up 50 seconds       443/tcp, 0.0.0.0:8899->80/tcp   my-nginx

[root@localhost ~]# vim /etc/sysconfig/iptables
.......
-A INPUT -p tcp -m state --state NEW -m tcp --dport 8899 -j ACCEPT

[root@localhost ~]# systemctl restart iptables.service

[root@localhost ~]# docker exec -ti my-nginx /etc/init.d/nginx start

然后就可以通过访问http://宿主机ip:8899,进而访问到nginx容器应用了。

接着测试下
[root@localhost ~]# mv /var/nginx/conf.d/default.conf /var/nginx/conf.d/default.conf.bak
[root@localhost ~]# cat /var/nginx/conf.d/test.conf
server {
listen 80;
server_name localhost;
location / {
root /var/web/www;
index index.html;
}
}

[root@localhost ~]# echo "12312313" > /var/www/html/test.html

接着重启容器的nginx应用
[root@localhost ~]# docker exec -t -i my-nginx /etc/init.d/nginx restart

测试访问(192.168.1.23是宿主机ip)
[root@localhost ~]# curl http://192.168.1.23:8899/
12313123

可以使用Nginx+Docker实现负载均衡

1)在本机部署两个nginx的docker容器,端口对应关系分别是8088:80、8089:80
2)在本机在安装nginx,然后在nginx配置文件中使用upstream将访问请求负载到本机的8088和8089端口上,
   这样也就是将访问请求负载到两个容器上了

此方案的原理是将宿主机的端口和docker容器的端口做一个映射(即访问宿主机的某端口会映射到docker容器对应的端口),
然后在宿主机通过配置Nginx,即可达到访问宿主机的某端口,按规则分配到指定的服务地址,即完成了负载均衡。

三、tomcat容器环境部署

[root@localhost ~]# docker images
REPOSITORY           TAG                 IMAGE ID            CREATED              SIZE
docker.io/centos     latest              67591570dd29        3 months ago         191.8 MB

[root@localhost ~]# docker run -it --name=container1 docker.io/centos
[root@9df6dc740f01 /]# java -version      //容器里安装java
 
上传宿主机的tomcat到容器里
[root@localhost ~]# cd /usr/local/src/
[root@localhost src]# ls
apache-tomcat-7.0.57.tar.gz
[root@localhost src]# docker cp apache-tomcat-7.0.57.tar.gz 9df6dc740f01:/usr/local/src/
 
登陆容器,安装tomcat
[root@9df6dc740f01 /]# cd /usr/local/src/
[root@9df6dc740f01 src]# ls
apache-tomcat-7.0.57.tar.gz
[root@9df6dc740f01 src]# tar -zvxf apache-tomcat-7.0.57.tar.gz
[root@9df6dc740f01 src]# mv apache-tomcat-7.0.57 /usr/local/tomcat7
 
将此容器提交为新的镜像
[root@localhost ~]# docker commit container1 tomcat7
sha256:2ec9e2eb978a4af266608fdfd70320bff0886b245a9a2d249cdefdfe70760acb
[root@localhost ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
tomcat7             latest              2ec9e2eb978a        3 minutes ago       562.3 MB
[root@localhost ~]# docker stop container1
container1
[root@localhost ~]# docker rm container1
container1
 
利用新提交的镜像启动tomcat容器
[root@localhost ~]# docker run -t -i -d --name=tomcat -p 8888:8080 tomcat7 /bin/bash
25f20fa6d54a1b2e2454a4d0a3966854e2fe4d81c54c366a1b07da47695f5418
[root@localhost ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                    NAMES
25f20fa6d54a        tomcat7             "/bin/bash"         3 seconds ago       Up 2 seconds        0.0.0.0:8888->8080/tcp   tomcat
 
登陆容器,启动tomcat进程
[root@localhost ~]# docker attach tomcat
[root@25f20fa6d54a ~]# /usr/local/tomcat7/bin/startup.sh
Using CATALINA_BASE:   /usr/local/tomcat7
Using CATALINA_HOME:   /usr/local/tomcat7
Using CATALINA_TMPDIR: /usr/local/tomcat7/temp
Using JRE_HOME:        /usr
Using CLASSPATH:       /usr/local/tomcat7/bin/bootstrap.jar:/usr/local/tomcat7/bin/tomcat-juli.jar
Tomcat started.
[root@25f20fa6d54a ~]# ps -ef|grep tomcat
root        62     1 92 07:52 ?        00:00:03 java -Djava.util.logging.config.file=/usr/local/tomcat7/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=/usr/local/tomcat7/endorsed -classpath /usr/local/tomcat7/bin/bootstrap.jar:/usr/local/tomcat7/bin/tomcat-juli.jar -Dcatalina.base=/usr/local/tomcat7 -Dcatalina.home=/usr/local/tomcat7 -Djava.io.tmpdir=/usr/local/tomcat7/temp org.apache.catalina.startup.Bootstrap start
root        84     1  0 07:52 ?        00:00:00 grep --color=auto tomcat

宿主机防火墙开通8888端口,然后就可以在外部容器的tomcat了(通过宿主机的8888端口进行映射)

[root@localhost ~]# vim /etc/sysconfig/iptables
.......
-A INPUT -p tcp -m state --state NEW -m tcp --dport 8888 -j ACCEPT
[root@localhost ~]# systemctl restart iptables.service
--------------------------------------------------------------------------------------------
在部署应用容器的时候,最好将容器的配置文件及数据目录跟宿主机目录做个映射关系!最好不要在容器内修改数据。
这样就可以通过宿主机的共享文件及共享目录去控制对应容器的数据了。
  
先启动tomcat容器,将tomcat的配置文件和数据目录跟宿主机做个映射。
[root@localhost ~]# docker cp tomcat:/usr/local/tomcat7/webapps /mnt/
[root@localhost ~]# docker cp tomcat:/usr/local/tomcat7/conf /mnt/
[root@localhost ~]# ls /mnt/conf/
catalina.policy  catalina.properties  context.xml  logging.properties  server.xml  tomcat-users.xml  web.xml
[root@localhost ~]# ls /mnt/webapps/
docs  examples  host-manager  manager  ROOT
  
然后关闭和删除这个tomcat容器,重启启动,启动时做目录映射关系
[root@localhost ~]# docker stop tomcat
tomcat
[root@localhost ~]# docker rm tomcat
tomcat
  
[root@localhost ~]# docker run -t -i -d --name=tomcat -v /mnt/webapps:/usr/local/tomcat7/webapps -v /mnt/conf:/usr/local/tomcat7/conf -p 8888:8080 tomcat7 /bin/bash
63799add4a628b1b690eb9e538001e6872b12e8e03e39b4e7275f7bf49c2645f
  
[root@localhost ~]# docker attach tomcat
[root@63799add4a62 /]# /usr/local/tomcat7/bin/startup.sh
Using CATALINA_BASE:   /usr/local/tomcat7
Using CATALINA_HOME:   /usr/local/tomcat7
Using CATALINA_TMPDIR: /usr/local/tomcat7/temp
Using JRE_HOME:        /usr
Using CLASSPATH:       /usr/local/tomcat7/bin/bootstrap.jar:/usr/local/tomcat7/bin/tomcat-juli.jar
Tomcat started.
  
......................温馨提示一下.....................
上面在创建容器时启动的进程是/bin/bash,容器创建成功后,需要启动创建里其他的进程,比如上面的tomcat进程。
那么除了上面直接登录容器内启动tomcat进程外,还可以在宿主机上通过docker exec启动(前提是容器在启动状态中)
 
docker exec 命令用户在运行状态中的容器内再次启动新的进程。命令格式:docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
[root@localhost ~]# docker exec tomcat /usr/local/tomcat7/bin/startup.sh   //如果启动中出现卡的情况,就ctrl+c,不影响启动结果
Tomcat started.

[root@linux-node2 ~]# docker attach my_tomcat
[root@f268eefdc283 /]# ps -ef|grep tomcat
root        30     0  1 10:13 ?        00:00:06 java -Djava.util.logging.config.file=/usr/local/tomcat7/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=/usr/local/tomcat7/endorsed -classpath /usr/local/tomcat7/bin/bootstrap.jar:/usr/local/tomcat7/bin/tomcat-juli.jar -Dcatalina.base=/usr/local/tomcat7 -Dcatalina.home=/usr/local/tomcat7 -Djava.io.tmpdir=/usr/local/tomcat7/temp org.apache.catalina.startup.Bootstrap start
root        76     1  0 10:23 ?        00:00:00 grep --color=auto tomcat
--------------------------------------------------------------------------------------------
如上在本机制作了tomcat7的镜像,可以将这个镜像上传到别的机器上进行tomcat容器部署
[root@localhost ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
tomcat7             latest              2ec9e2eb978a        39 minutes ago      562.3 MB
  
[root@localhost ~]# docker save tomcat7 > /opt/tomcat7.tar.gz
[root@localhost ~]# rsync -e "ssh -p22" -avpgolr /opt/tomcat7.tar.gz 192.168.1.17:/opt/
  
然后在192.168.1.17机器上部署tomcat容器
[root@linux-node2 ~]# docker images
REPOSITORY                   TAG                 IMAGE ID            CREATED             SIZE
tomcat7                      latest              2ec9e2eb978a        58 minutes ago      562.3 MB
[root@linux-node2 ~]# docker run -t -i -d --name=my_tomcat tomcat7 /bin/bash
8657fa536c4a6308801d96b585671a22d08795bd891b0b2b20d86b843cde0040
[root@linux-node2 ~]# docker attach my_tomcat
[root@8657fa536c4a /]# /usr/local/tomcat7/bin/startup.sh
Using CATALINA_BASE:   /usr/local/tomcat7
Using CATALINA_HOME:   /usr/local/tomcat7
Using CATALINA_TMPDIR: /usr/local/tomcat7/temp
Using JRE_HOME:        /usr
Using CLASSPATH:       /usr/local/tomcat7/bin/bootstrap.jar:/usr/local/tomcat7/bin/tomcat-juli.jar
Tomcat started.
--------------------------------------------------------------------------------------------

四、Mysql容器环境部署

[root@localhost ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
docker.io/centos    latest              67591570dd29        3 months ago        191.8 MB

启动容器,进入容器内编译安装mysql
[root@localhost ~]# docker run -t -i docker.io/centos /bin/bash
[root@2ccd29e52286 /]#  rpm -qa | grep mysql       //确保没有自带安装mysql,有的话就卸载
[root@2ccd29e52286 /]#  yum -y install make gcc-c++ cmake bison-devel ncurses-devel
[root@2ccd29e52286 /]# groupadd mysql 
[root@2ccd29e52286 /]# useradd -g mysql mysql -M -s /sbin/nologin
[root@2ccd29e52286 /]# cd /usr/local/src
[root@2ccd29e52286 src]# wget -c http://ftp.ntu.edu.tw/MySQL/Downloads/MySQL-5.6/mysql-5.6.34.tar.gz
[root@2ccd29e52286 src]# tar -zxvf mysql-5.6.34.tar.gz
[root@2ccd29e52286 src]# cd mysql-5.6.34/
[root@2ccd29e52286 mysql-5.6.34]# cmake -DCMAKE_INSTALL_PREFIX=/usr/local/mysql -DMYSQL_DATADIR=/data/mysql/data -DSYSCONFDIR=/etc -DWITH_MYISAM_STORAGE_ENGINE=1 -DWITH_INNOBASE_STORAGE_ENGINE=1 -DWITH_MEMORY_STORAGE_ENGINE=1 -DWITH_READLINE=1 -DMYSQL_UNIX_ADDR=/var/lib/mysql/mysql.sock -DMYSQL_TCP_PORT=3306 -DENABLED_LOCAL_INFILE=1 -DWITH_PARTITION_STORAGE_ENGINE=1 -DEXTRA_CHARSETS=all -DDEFAULT_CHARSET=utf8 -DDEFAULT_COLLATION=utf8_general_ci
[root@2ccd29e52286 mysql-5.6.34]# make && make install

[root@2ccd29e52286 mysql-5.6.34]# mkdir -p /data/mysql/data
[root@2ccd29e52286 mysql-5.6.34]# chown -R mysql:mysql /usr/local/mysql
[root@2ccd29e52286 mysql-5.6.34]# chown -R mysql:mysql /data/mysql/data

初始化mysql
[root@2ccd29e52286 mysql-5.6.34]# cd /usr/local/mysql
[root@2ccd29e52286 mysql]# ./scripts/mysql_install_db --basedir=/usr/local/mysql --datadir=/data/mysql/data --user=mysql
-------------------------------------------------------------------------------------------
如果报错:FATAL ERROR: please install the following Perl modules before executing ./scripts/mysql_install_db: Data::Dumper

解决办法:
[root@2ccd29e52286 mysql]# yum install -y perl-Module-Install.noarch 
------------------------------------------------------------------------------------------

启动mysql,并设置密码
[root@2ccd29e52286 mysql]# cp support-files/mysql.server /etc/init.d/mysql
[root@2ccd29e52286 mysql]# /etc/init.d/mysql start
[root@2ccd29e52286 mysql]# mysql -uroot
.....
修改root密码,执行命令如下
mysql> SET PASSWORD = PASSWORD('123456');

若要设置root用户可以远程访问,执行
mysql> GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'password' WITH GRANT OPTION;
使授权立即生效
mysql> FLUSH PRIVILEGES;

提交为新镜像
[root@localhost ~]# docker ps 
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
2ccd29e52286        docker.io/centos    "/bin/bash"         3 hours ago         Up 3 hours                              modest_bose
[root@localhost ~]# docker commit 2ccd29e52286 mysql
sha256:3b965b11e7a01b9422c8d82a8352c60c83545698309d9511b4df6371bcfcd6a1
[root@localhost ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
mysql               latest              3b965b11e7a0        6 minutes ago       4.511 GB
docker.io/centos    latest              67591570dd29        3 months ago        191.8 MB

根据新提交的镜像,启动mysql容器
[root@localhost ~]# docker stop 2ccd29e52286
2ccd29e52286
[root@localhost ~]# docker rm 2ccd29e52286        //当然这个之前启动的容器也可以不删除,忽略就行。
2ccd29e52286

[root@localhost ~]# docker run -t -i -d --name=my_mysql -p 33061:3306 mysql /bin/bash
a02f56c3e7313733bcd58414d5dcd5501f8504352206ee321e9e2aeab15d6269

[root@localhost ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                     NAMES
a02f56c3e731        mysql               "/bin/bash"         7 seconds ago       Up 6 seconds        0.0.0.0:33061->3306/tcp   my_mysql

启动容器的mysql服务方法(也可以在上面创建容器的时候直接启动,即将/bin/bash命令换成mysql启动命令):
1)直接在宿主机上通过docker exec命令启动
[root@localhost ~]# docker exec my_mysql /etc/init.d/mysql start        //如果启动后出现卡的情况,就ctrl+c,不影响启动结果
Starting MySQL SUCCESS! 
2)登陆容器内启动
[root@localhost ~]# docker attach my_mysql
[root@a02f56c3e731 /]# /etc/init.d/mysql start
Starting MySQL SUCCESS!

查看容器启动的进程
[root@localhost ~]# docker top my_mysql
UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
root                7340                28948               0                   14:21               pts/1               00:00:00            /bin/bash
root                8595                7340                0                   14:28               pts/1               00:00:00            /bin/sh /usr/local/mysql//bin/mysqld_safe --datadir=/data/mysql/data --pid-file=/data/mysql/data/mysql.pid
mysql               9376                8595                0                   14:28               pts/1               00:00:00            /usr/local/mysql/bin/mysqld --basedir=/usr/local/mysql/ --datadir=/data/mysql/data --plugin-dir=/usr/local/mysql//lib/plugin --user=mysql --log-error=/data/mysql/data/mysql-error.log --pid-file=/data/mysql/data/mysql.pid --socket=/usr/local/mysql/var/mysql.sock --port=3306

登陆容器查看
[root@a02f56c3e731 /]# netstat -tunlp         //首先yum安装net-tools
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN      -   

在容器内的mysql里写入一些数据
[root@a02f56c3e731 /]# /usr/local/mysql/bin/mysql -p123456
Warning: Using a password on the command line interface can be insecure.
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (111)

[root@a02f56c3e731 /]# ln -s /usr/local/mysql/var/mysql.sock  /var/lib/mysql/mysql.sock
ln: failed to create symbolic link '/var/lib/mysql/mysql.sock': File exists
[root@a02f56c3e731 /]# rm -f /var/lib/mysql/mysql.sock
[root@a02f56c3e731 /]# ln -s /usr/local/mysql/var/mysql.sock  /var/lib/mysql/mysql.sock

[root@a02f56c3e731 /]# /usr/local/mysql/bin/mysql -p123456
.......
mysql> create database wangshibo;
Query OK, 1 row affected (0.00 sec)

mysql> use wangshibo;
Database changed
mysql> create table hehe(
    -> id int(3),
    -> name varchar(10)
    -> );
Query OK, 0 rows affected (0.03 sec)

mysql> insert into hehe values(1,"wanglei");
Query OK, 1 row affected (0.01 sec)

mysql> insert into hehe values(2,"zhaomin");
Query OK, 1 row affected (0.01 sec)


查看容器ip,可以登陆容器内ifconfig查看(首先要yum安装net-tools)
[root@a02f56c3e731 /]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.2  netmask 255.255.0.0  broadcast 0.0.0.0
        inet6 fe80::42:acff:fe11:2  prefixlen 64  scopeid 0x20<link>
        ether 02:42:ac:11:00:02  txqueuelen 0  (Ethernet)
        RX packets 117  bytes 319373 (311.8 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 102  bytes 7042 (6.8 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 0  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

或者在宿主机使用docker inspect命令查看容器ip
[root@localhost ~]# docker inspect my_mysql|grep IPAddress
            "SecondaryIPAddresses": null,
            "IPAddress": "172.17.0.2",
                    "IPAddress": "172.17.0.2",


在宿主机本地连接容器的mysql
[root@localhost ~]# mysql -u root -h 172.17.0.2 -p123456
ERROR 1130 (HY000): Host '172.17.0.1' is not allowed to connect to this MySQL server
出现错误的原因:
容器的网络ip是根据宿主机的虚拟桥接网卡docker0自动分配的,而docker0的ip默认是172.17.0.1.
容器的mysql内需要给这个ip授权。
[root@localhost ~]# ifconfig
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 0.0.0.0
..........

登陆容器内的mysql,进行授权
[root@a02f56c3e731 /]# /usr/local/mysql/bin/mysql -p123456
.......
mysql> select host,user,password from mysql.user;
+--------------+------+-------------------------------------------+
| host         | user | password                                  |
+--------------+------+-------------------------------------------+
| localhost    | root | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 |
| 2ccd29e52286 | root |                                           |
| 127.0.0.1    | root |                                           |
| ::1          | root |                                           |
| localhost    |      |                                           |
| 2ccd29e52286 |      |                                           |
+--------------+------+-------------------------------------------+
6 rows in set (0.00 sec)

mysql> grant all privileges on *.* to root@'%' identified by "123456";
Query OK, 0 rows affected (0.00 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

mysql> select host,user,password from mysql.user;
+--------------+------+-------------------------------------------+
| host         | user | password                                  |
+--------------+------+-------------------------------------------+
| localhost    | root | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 |
| 2ccd29e52286 | root |                                           |
| 127.0.0.1    | root |                                           |
| ::1          | root |                                           |
| localhost    |      |                                           |
| 2ccd29e52286 |      |                                           |
| %            | root | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 |
+--------------+------+-------------------------------------------+
8 rows in set (0.00 sec)

再次在宿主机本机尝试连接容器的mysql,发现可以正常连接!
[root@localhost ~]# mysql -u root -h 172.17.0.2 -p123456
.......
MySQL [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test               |
| wangshibo          |
+--------------------+
5 rows in set (0.01 sec)

MySQL [(none)]> select * from wangshibo.hehe;
+------+---------+
| id   | name    |
+------+---------+
|    1 | wanglei |
|    2 | zhaomin |
+------+---------+
2 rows in set (0.00 sec)


---------------------------------------------------------------------------------------------------
也可以再创建一个容器,使用--link进行容器链接。
这里需要特别注意一下"--link=my_mysql:mydb"(中间可以使用=,也可以空格隔开),这个参数是告诉容器需要使用my_mysql容器,并将其别名命名为mydb,这样在这两个容器里就可以使用mydb来作为提供mysql数据库服务的机器名。
[root@localhost ~]#  docker run --rm -it --name mymysql2 --link my_mysql:mydb docker.io/centos /bin/bash
[root@f1534ad473f4 /]# cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2  mydb 33d784ee3121 my_mysql
172.17.0.4  f1534ad473f4

[root@f1534ad473f4 /]# mysql -u root -h mydb -p123456
......
MySQL [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test               |
| wangshibo          |
+--------------------+
5 rows in set (0.00 sec)

MySQL [(none)]> select * from wangshibo.hehe;
+------+---------+
| id   | name    |
+------+---------+
|    1 | wanglei |
|    2 | zhaomin |
+------+---------+
2 rows in set (0.00 sec)

------------------------------------------------------------------------------------------------

在外部连接my_mysql容器内的mysql,就需要通过映射到宿主机的33061端口了(首先在宿主机的iptables里开放33061端口的访问)
[root@localhost ~]# vim /etc/sysconfig/iptables
......
-A INPUT -p tcp -m state --state NEW -m tcp --dport 33061 -j ACCEPT
[root@localhost ~]# systemctl restart iptables.service 

这样在远程,就可以使用宿主机的映射端口33061访问容器mysql (使用-P指定端口进行mysql的连接)
[root@huanqiu_web1 ~]# mysql -uroot -h103.10.86.23 -P33061 -p123456
.......
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test               |
| wangshibo          |
+--------------------+
5 rows in set (0.00 sec)

mysql> select * from wangshibo.hehe;
+------+---------+
| id   | name    |
+------+---------+
|    1 | wanglei |
|    2 | zhaomin |
+------+---------+
2 rows in set (0.00 sec)

mysql> 

---------------------------------------------------------------------------------------- 上面容器内使用的是编译安装mysql,也可以yum安装:

[root@localhost ~]# docker run -t -i --privileged -i --name=wang docker.io/centos /sbin/init     //容器启动后,会一直在卡着的状态中,先不用管,打开另一个终端窗口执行下面命令登陆容器
[root@localhost ~]# docker exec -it wang /bin/bash
[root@e9efd323782a /]# yum install -y wget net-tools
[root@e9efd323782a /]# wget http://dev.mysql.com/get/mysql-community-release-el7-5.noarch.rpm
[root@e9efd323782a /]# rpm -ivh mysql-community-release-el7-5.noarch.rpm
[root@e9efd323782a /]# yum install mysql-community-server
[root@e9efd323782a /]# systemctl start mysqld
[root@e9efd323782a /]# lsof -i:3306
COMMAND PID  USER   FD   TYPE   DEVICE SIZE/OFF NODE NAME
mysqld  453 mysql   10u  IPv6 32200473      0t0  TCP *:mysql (LISTEN)

其他应用容器的部署与上面操作类似~