Docker操作日记(二)----创建一个自己的Docker image来部署

上一篇讲了怎么安装Docker和运行hello-world的docker image。 现在我们就说说怎么去创建一个自己的Docker image。 这里,我示例去创建一个Tomcat+我们自己的JAVA Web App的image。

这个过程分下面几部:

1. 下载一个原始的image,后面工作都基于这个image来开展。 我们这里是下载一个tomcat的image。

2. 启动一个tomcat的docker实例,然后修改一些配置,然后用这个实例的ID来生成一个新的image叫mytomcat

3. 编写一个DockerFile, 通过这个DockerFile来生成我们自己myapp的Docker image, 运行并看效果

4. 创建一个本地的repository,把MyWebApp提交到本地repository

5. 一些情况的说明

 

第一步, 我们来下载一个原始的tomcat到本地:

你先用docker search 命令来查一下,有多少与tomcat相关的image在公共的repository, 然后选中其中一个下载

$ sudo docker search tomcat

NAME                               DESCRIPTION                            STARS     OFFICIAL   AUTOMATED
tomcat                               Apache Tomcat ...                       1193           [OK]
dordoka/tomcat                 Tomcat 8 ba...                             31                             [OK]
davidcaste/alpine-tomcat    Apache Tomcat 7/8 ...                 15                            [OK]
cloudesire/tomcat               Tomcat server, 6/7/8                   12                            [OK]
 

$ sudo docker pull tomcat

Digest: sha256:0fb173e213111be292962336777a134d43f59c1b8cc2da3cbaaf6308ee7a490a
Status: Downloaded newer image for tomcat:latest
注: pull的动作可能会因为网络的问题失败,请多试几次。

$ sudo docker images tomcat
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
tomcat              latest              0335e4e8579b        3 days ago          355 MB

 

第二步启动tomcat的实例,修改配置

$ sudo docker run -it -v /home/master/program:/mnt/software  tomcat /bin/bash

注: -it 是有标准输出选项, -v是主机目录到docker容器目录映射, /bin/bash是启动后第一个CMD

进入tomcat 实例的控制台之后,拷贝 tomcat的server.xml文件和 Java的java.security文件到/mnt/software下。 这个是因为这个tomcat实例里没有任何编辑工具(vi都没有),所以我们不得不拷贝他们到映射文件下(这样主机就可以访问),在主机上编辑他们.

[容器内]# cp /usr/local/tomcat/conf/server.xml /mnt/software

[容器内]# cp /etc/java-7-openjdk/security/java.security /mnt/software

在server.xml文件中,appBase改为docker_app,这是因为我们的web app的代码都会部署在/usr/local/tomcat/docker_app,所以我们修改配置文件,让应用目录指向这个文件夹。

 <Host name="localhost"  appBase="docker_app"
            unpackWARs="true" autoDeploy="true">
 

 

在java.security中,修改securerandom.source的值,这是因为如果securerandom.source使用默认值的话,会在tomcat启动会耗费很长时间(这个网上有解释,读者可以自己去搜搜)

securerandom.source=file:/dev/./urandom

然后把修改好的文件,覆盖原来的文件

[容器内]#  cp -f /mnt/software/java.security /etc/java-7-openjdk/security/

[容器内]#    cp -f /mnt/software/server.xml /usr/local/tomcat/conf/

接下来退出容器实例,然后用这个实例ID生成一个新的新的image叫mytomcat

[容器内]#    exit

$ sudo docker ps --last 1
CONTAINER ID   IMAGE   COMMAND      CREATED     STATUS                  PORTS               NAMES
7c456c4b41d1     tomcat  "/bin/bash"      31 minutes ago    Exited (0) 37 seconds ago       serene 
 

$ sudo docker commit 7c45 mytomcat
sha256:c795645c8ad718b60f603cb1514d7e9f65eae6773d851b8738d4a556d52d7c03

docker commit 后面containerID,只要取前四位即可。 然后检查一下image是否已经生成。

$ sudo docker images mytomcat
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
mytomcat            latest              c795645c8ad7        12 minutes ago      355 MB

OK, 万事俱备就差东风了。

 

第三步,编写一个DockerFile, 通过这个DockerFile来生成我们自己myapp的Docker image, 运行并看效果

让我们创建APP的工作目录,在工作目录下创建Dockerfile文件和拷贝我们的可执行代码到这个目录下(注,可执行代码必须和Dockerfile在同一目录下。 但是文档上说ADD的指令能支持URL地址,我没试过)

$ mkdir /home/master/program/app_compose

$ cd  /home/master/program/app_compose

$ cp -rf /我们的代码目录/image_code  /home/master/program/app_compose/ 

$ vi Dockfile

        FROM mytomcat
        ADD  image_code/  /usr/local/tomcat/
        EXPOSE 8080
        ENTRYPOINT ["/usr/local/tomcat/bin/catalina.sh"]
        CMD ["run"]

FROM是指明原始的image的出处,这里我用的是我们刚刚生成的image, ADD是拷贝一个主机的目录到容器里的某个目录下,这里我是拷贝代码文件夹到tomcat的下做为appBase目录, EXPOSE是指明容器侦听的端口(需要在run的时候指明外界与之对应的外部端口),ENTRYPOINT是容器启动的入口接口,CMD是入口接口的参数。

注: image_code目录结构:$  ls program/app_compose/image_code/docker_app/ROOT/
                                           META-INF/ WEB-INF/
 

现在可以来生成APP 1.0的image(name是myapp, tag是1.0-init, 以后更新,我们只改tag)

$ sudo docker build --rm --tag myapp:1.0-init  /home/master/program/app_compose/

执行完成之后,可以看到image已经生成了:

$ sudo docker images myapp
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
myapp               1.0-init            1d8711421563        34 minutes ago      360 MB

启动它,来看看效果

$ sudo docker run -it -p 8080:8080 myapp:1.0-init
-it是为了你能看到有log输出, 如果你让它运行在后台,你把-it改成-d就行了; -p是指定端口映射HOST_port : CONTAINER_PORT

在浏览器里输入 http://你的公网IP:8080/   就能看到效果了。 

下次更新应用的时候,只要更新image_code里面的文件,重新执行docker build就生成新的image,非常方便。 

需要停止docker实例的运行,可以先用docker ps查看当前运行的实例,然后用docker kill 实例ID(前四位即可),来停止一个实例运行。

 

第四步, 创建一个本地的repository,把myapp提交到本地repository

我们已经创建了myapp的image,在本机使用已经没有问题。当然,你可以通过docker save/load 来保持image到一个文件,通过文件的转移,在其他机器上运行这个image。 但是你无法使用文件的方式在swarm集群中使用。 所以,你需要提交到相关机器都能看到的repository里,一般来说有2个选择: 1. 提交的docker的官方HUB (https://hub.docker.com/)2. 在本地网络里,创建一个本地的repository. 

这里,我们就讲一下怎么创建一个本地repository:

首先,要做一件事情去除https错误,因为docker默认用https去获取镜像的,但是如果你本地没有设置https服务的话,在从私有仓库pull镜像的时候,会出现一个错误。

新建一个/etc/docker/daemon.json,在这里添加:

{ "insecure-registries":["你的创建私有仓库的机器IP:5000"] }

在swarm集群网络的每台机器都要添加这个文件.

1. 下载registry的image(pull可能连接timout,可以多试几次), 并运行registry在后台

$ sudo docker pull registry

$ sudo docker run -d -p 5000:5000 registry

查看一下是否已经运行

$ sudo docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS             
f57efc7e30df           registry            "/entrypoint.sh /e..."      About a minute ago 

2. 把我们刚才创建myapp的image提交到本地repository

$sudo docker tag myapp:1.0-init 172.19.187.96:5000/myapp:1.0-init

$ sudo docker push 172.19.187.96:5000/myapp:1.0-init

先打一个tag标签,然后提交。  172.19.187.96是我运行机器的内网IP

查看一下image的情况

$ sudo docker images
REPOSITORY                       TAG                 IMAGE ID            CREATED             SIZE
172.19.187.96:5000/myapp   1.0-init            1d8711421563        About an hour ago   360 MB
myapp                                 1.0-init            1d8711421563        About an hour ago   360 MB
 

在slaver机器上,运行 $ sudo docker pull 172.19.187.96:5000/myapp:1.0-init 就可以下载image了。 

把image提交到respository的主要用途,是为了后面swarm模式集群的应用部署做准备。

 

第五,一些情况的说明

1. 更新app, 只要更新代码文件夹,按照第三和第四步,重新build和提交就可以了。

2. 关于在容器内运行程序的权限的问题

之前,我曾经想下一个纯的centos的image,然后在里面安装我们任何想装的service比如tomcat等等,但是我碰到一个关于权限的问题, 在容器内,我无法使用systemctl启动一个service,会返回一个D-BUS什么什么的错误。 查了网上的资料,据说是CentOS7的docker image的bug(原因是说systemd在centos被删除了:systemd in CentOS 7 has been removed and replaced with a fakesystemd package for dependency resolution. This is due to systemd requiring the CAP_SYS_ADMIN capability)。

网上有一个解决办法来处理这个问题,据说最新版的centos已经解决这个问题,但是需要安装下列的Dockerfile来配置:

FROM centos:7
MAINTAINER "you" <your@email.here>
ENV container docker
RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == \
systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*;
VOLUME [ "/sys/fs/cgroup" ]
CMD ["/usr/sbin/init"]
 

生成image之后,可以用  sudo docker run --privileged [其他options]  image名 来运行。--priviledged是必须的选项,给与容器实例一个超级权限。 的确这样方式,可以得到最初设想的image(包含很多后装的service 比如sshd, tomcat等等)。  但是当我用这个image去跑swarm模式的时候,当启动swarm service碰到了一个问题,docker service create 不支持--privileged参数,也没有任何相关的权限参数,导致的结果是docker 容器无法启动。 

看了很多的资料,发现很多跟权限相关的选项或者命令,在swarm模式下都不支持。 比如在Dockerfile的指令里,CAPS_ADD/CAPS_DROP等在swarm模式下都不支持。 

仔细想想,可能原因是在swarm模式,service部署是leader机一条命令部署,全部子节点都会被更新。 在本机上你可以命令的方式要求一个超级权限,但是在子节点那里,通过work代理,可能暂时不支持对权限动态申请(我猜的^_^)。

这里又引申出一个问题,进入到docker实例中的时候,我能看到在docker中的身份是root,那root为什么还有申请权限。 想起自己在2013年的工作经历,那时候做系统安全,要求把一些危险的APP放在LXC(linux container)里,我们在创建LXC实例,就会分配好哪些capabilities, 那些危险的APP即使在容器内取得ROOT权限,它们只能用到我们分配的权限,其他的,它们do nothing。 现在docker是基于LXC,我猜想此root非彼root的问题是同样的原因。

 

下一篇,我们来介绍一下怎么用搭建swarm的集群

转载于:https://my.oschina.net/u/3128310/blog/841736

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值