一、简介
创建docker镜像有2种方式:
- 在已有镜像上修改,将修改后的镜像提交为新镜像
- 编写docker file,使用docker build根据docker file创建一个新镜像
二、过程
1 修改已有镜像
在win10上操作,linux下操作类似;以mysql为例
1.1 准备一个mysql镜像
1.1.1 搜索mysql镜像
C:\Users\username>docker search mysql
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
mysql MySQL is a widely used, open-source relation… 10380 [OK]
mariadb MariaDB is a community-developed fork of MyS… 3848 [OK]
mysql/mysql-server Optimized MySQL Server Docker images. Create… 758 [OK]
percona Percona Server is a fork of the MySQL relati… 519 [OK]
centos/mysql-57-centos7 MySQL 5.7 SQL database server 87
mysql/mysql-cluster Experimental MySQL Cluster Docker images. Cr… 79
centurylink/mysql Image containing mysql. Optimized to be link… 60 [OK]
bitnami/mysql Bitnami MySQL Docker Image 47 [OK]
deitch/mysql-backup REPLACED! Please use http://hub.docker.com/r… 41 [OK]
tutum/mysql Base docker image to run a MySQL database se… 35
databack/mysql-backup Back up mysql databases to... anywhere! 35
prom/mysqld-exporter 34 [OK]
schickling/mysql-backup-s3 Backup MySQL to S3 (supports periodic backup… 29 [OK]
linuxserver/mysql A Mysql container, brought to you by LinuxSe… 27
centos/mysql-56-centos7 MySQL 5.6 SQL database server 20
circleci/mysql MySQL is a widely used, open-source relation… 20
arey/mysql-client Run a MySQL client from a docker container 17 [OK]
mysql/mysql-router MySQL Router provides transparent routing be… 17
fradelg/mysql-cron-backup MySQL/MariaDB database backup using cron tas… 10 [OK]
yloeffler/mysql-backup This image runs mysqldump to backup data usi… 7 [OK]
openshift/mysql-55-centos7 DEPRECATED: A Centos7 based MySQL v5.5 image… 6
devilbox/mysql Retagged MySQL, MariaDB and PerconaDB offici… 3
ansibleplaybookbundle/mysql-apb An APB which deploys RHSCL MySQL 2 [OK]
jelastic/mysql An image of the MySQL database server mainta… 1
widdpim/mysql-client Dockerized MySQL Client (5.7) including Curl… 1 [OK]
1.1.2 下载mysql镜像,这里我选择官方的star数最多的
C:\Users\username>docker pull mysql
Using default tag: latest
latest: Pulling from library/mysql
a076a628af6f: Pull complete
f6c208f3f991: Pull complete
88a9455a9165: Pull complete
406c9b8427c6: Pull complete
7c88599c0b25: Pull complete
25b5c6debdaf: Pull complete
43a5816f1617: Pull complete
69dd1fbf9190: Pull complete
5346a60dcee8: Pull complete
ef28da371fc9: Pull complete
fd04d935b852: Pull complete
050c49742ea2: Pull complete
Digest: sha256:0fd2898dc1c946b34dceaccc3b80d38b1049285c1dab70df7480de62265d6213
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest
1.2 修改镜像
1.2.1 根据下载好的镜像启动一个容器
C:\Users\username>docker run -itd --name my_mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql
09d35b16774268a41b058757d156bb4c66c0c0007fc4246b67cec6df7573ca5d
参数说明
- -i 开启标准输入
- -t 开启tty,-it表示开启一个交互式的bash shell
- -d 后台运行容器,并打印容器id
- –name my_mysql 指定容器名字为my_mysql
- p 3306:3306 自定义端口映射,将容器的3306端口映射到宿主机的3306端口
- -e MYSQL_ROOT_PASSWORD=123456
- mysql 要启动的镜像名
- 09d35b16774268a41b058757d156bb4c66c0c0007fc4246b67cec6df7573ca5d
1.2.2 创建一个新用户
使用navicat或者dbeaver等连接工具,连接mysql,ip为localhost,用户名为root,password为123456
执行下面的sql添加一个用户
CREATE USER 'zhangsan'@'%' IDENTIFIED BY 'zhangsan';
1.3 提交修改后的镜像
C:\Users\username>docker commit -m="mawenbin has update" -a="mawenbin" 79dde6333ffb mawenbin/mysql:v0
sha256:7dcee12292a1ee86c4487197dd8560de3c1940c0c1d670e09647dc6e7e748ec8
参数说明
- -m 类似git commit -m,提交时的注释
- -a 作者
- 79dde6333ffb 根据哪个容器id生成镜像
- mawenbin/mysql:v0 冒号前的mawenbin/mysql为镜像名,冒号后的v0为镜像的标签
1.4 查看创建的新镜像
C:\Users\username>docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mawenbin/mysql v0 7dcee12292a1 20 hours ago 565MB
mawenbin/mysql v2 28e3f407de32 22 hours ago 565MB
mysql latest d4c3cafb11d5 2 days ago 565MB
ubuntu 15.10 9b9cb95443b5 4 years ago 157MB
启动新镜像看mysql的user表已经有zhangsan用户,验证过程就不详细说明了
2 根据docker file创建新镜像
在win10上未成功,果断切换到linux
2.1 创建一个Dockerfile文件
注意:文件名必须为Dockerfile
mkdir /opt/dockerfile1
cd /opt/dockerfile1
cat Dockerfile
FROM ansible/centos7-ansible
RUN /bin/echo 'root:123456' |chpasswd
RUN useradd test1
RUN /bin/echo 'test1:123456' |chpasswd
RUN /bin/echo -e "LANG=\"en_US.UTF-8\"" > /etc/default/local
EXPOSE 22
EXPOSE 80
CMD /usr/sbin/sshd -D
每一个指令都会基于镜像创建一个新的层,每一个指令的前缀都必须是大写的。
指令含义:
- FROM 指定基于哪个镜像源构建,这里我们基于ansible/centos7-ansible构建
- RUN 告诉docker在镜像内执行一个程序或命令
- RUN /bin/echo ‘root:123456’ |chpasswd 修改root密码为123456
- RUN useradd test1 添加用户名为test1的新用户
- RUN /bin/echo ‘test1:123456’ |chpasswd
- RUN /bin/echo -e "LANG=“en_US.UTF-8"” > /etc/default/local 设置程序运行的语言环境为en_US.UTF-8
- EXPOSE 暴露端口
- EXPOSE 22 暴露22端口
- EXPOSE 80 暴露80端口
- CMD 类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:
- CMD 在docker run 时运行
- RUN 是在 docker build时运行
- CMD /usr/sbin/sshd -D 在启动容器时,以非后台守护进程的方式运行ssh服务
Dockerfile详细参考文档:
https://www.runoob.com/docker/docker-dockerfile.htmlhttps://docs.docker.com/engine/reference/builder/
2.2 执行build命令
# docker build -t test/centos7 .
Sending build context to Docker daemon 2.048 kB
Step 1/8 : FROM ansible/centos7-ansible
---> 688353a31fde
Step 2/8 : RUN /bin/echo 'root:123456' |chpasswd
---> Using cache
---> ada238567b9e
Step 3/8 : RUN useradd test1
---> Using cache
---> 96ae8562d37a
Step 4/8 : RUN /bin/echo 'test1:123456' |chpasswd
---> Using cache
---> 2947b5ff2ed8
Step 5/8 : RUN /bin/echo -e "LANG=\"en_US.UTF-8\"" > /etc/default/local
---> Running in 178ee221d502
---> 689f168e9f9d
Removing intermediate container 178ee221d502
Step 6/8 : EXPOSE 22
---> Running in 4b6d1c193ecb
---> 4f9898dfbd66
Removing intermediate container 4b6d1c193ecb
Step 7/8 : EXPOSE 80
---> Running in 1230b660cdec
---> e9ea05c0567f
Removing intermediate container 1230b660cdec
Step 8/8 : CMD /usr/sbin/sshd -D
---> Running in 9edebbd83def
---> f840cb06b100
Removing intermediate container 9edebbd83def
Successfully built f840cb06b100
一个基于centos7-ansible的镜像就构建成功了
指令含义:
- -t test/centos7 指定新创建的镜像名为test/centos7
- . 最后点的意思为基于当前目录下的Dockerfile构建,所有要打到镜像里的东西最好放到Dockerfile所在目录
三、常用案例
以下案例建议在linux上操作
1 构建java程序镜像
1.1准备jar包和jre包
1.1.1 jar包
代码如下
/*
* This Java source file was generated by the Gradle 'init' task.
*/
package test_gradle_java;
public class App {
public String getGreeting() {
return "Hello World!";
}
public static void main(String[] args) {
System.out.println(new App().getGreeting());
}
}
打出的jar包名为:app-1.0.0.jar
1.1.2 下载jar包对应的jre版本
jre8下载地址 我编写java代码使用的java版本为jdk8,运行java只需要jre即可(jdk也可以,这里为了打出的镜像小一些所以只要jre),这里下载的是jre-8u271-linux-x64.tar.gz
1.2创建目录,上传jar包
mkdir /opt/tmp/docker_java1
cd /opt/tmp/docker_java1
用xshell,或其他工具上传到创建的目录下
1.3 创建Dockerfile文件
cat Dockerfile
# 基于ansible/centos7-ansible创建
FROM ansible/centos7-ansible
# 拷贝当前目录下的jre-8u271-linux-x64.tar.gz到容器内的/usr/java/jdk
ADD jre-8u271-linux-x64.tar.gz /usr/java/jdk
# 设置java的环境变量JAVA_HOME为/usr/java/jdk/jre1.8.0_271
ENV JAVA_HOME /usr/java/jdk/jre1.8.0_271
# 把JAVA_HOME追加到PATH
ENV PATH ${PATH}:${JAVA_HOME}/bin
# 拷贝app-1.0.0.jar到容器内的/opt/jars/app-1.0.0.jar
COPY app-1.0.0.jar /opt/jars/app-1.0.0.jar
# 启动容器时调用的命令
CMD java -cp /opt/jars/app-1.0.0.jar test_gradle_java.App
现在jar包,jre,Dockerfile都已经准备好
ls
app-1.0.0.jar Dockerfile jre-8u271-linux-x64.tar.gz
1.4 执行构建命令
docker build -t app:v1.0.0 .
Sending build context to Docker daemon 93.12 MB
Step 1/6 : FROM ansible/centos7-ansible
---> 688353a31fde
Step 2/6 : ADD jre-8u271-linux-x64.tar.gz /usr/java/jdk
---> 2709bc7d542c
Removing intermediate container 19575602dffa
Step 3/6 : ENV JAVA_HOME /usr/java/jdk/jre1.8.0_271
---> Running in f95d6bebe5c0
---> d6f859ac28c2
Removing intermediate container f95d6bebe5c0
Step 4/6 : ENV PATH ${PATH}:${JAVA_HOME}/bin
---> Running in 3c32809f6a78
---> 33f3d26a5098
Removing intermediate container 3c32809f6a78
Step 5/6 : COPY app-1.0.0.jar /opt/jars/app-1.0.0.jar
---> 2b1dac0a379d
Removing intermediate container 44d6f68b5828
Step 6/6 : CMD java -cp /opt/jars/app-1.0.0.jar test_gradle_java.App
---> Running in 1fbccdfa97b3
---> 2680ec4a21ab
Removing intermediate container 1fbccdfa97b3
Successfully built 2680ec4a21ab
1.5 查看创建镜像
docker images -a
REPOSITORY TAG IMAGE ID CREATED SIZE
app v1.0.0 2680ec4a21ab 4 minutes ago 698 MB
查看所有镜像,发现已经有一个app:v1.0.0的镜像了
1.5 创建容器验证执行jar包
docker run --name appv1 app:v1.0.0
Hello World!
可以看到程序的输出已经打印,至此java镜像已构建成功
2 构建python程序镜像
2.1 准备所需代码,requirements.txt,Dockerfile
2.1.1 准备python代码
源码:
# coding:utf8
print("Helloworld")
2.1.2 生成项目依赖
项目在win10 编写的情况下
# 如果有使用virtualenv环境,需要先执行激活命令;命令位置,win10:($VIRTUALENV/script/activate.bat),linux:(source $VIRTUALENV/bin/activate)
pip freeze > requirements.txt
2.1.3 编写Dockerfile
# 基于python3.7构建
FROM python:3.7
# 设置代码文件夹工作目录 /opt
WORKDIR /opt
# 复制当前文件到容器中的目录/opt
ADD . /opt
# 安装所需的包
RUN pip install -r /opt/app/requirements.txt
# Run app.py when the container launches
CMD python /opt/app/app.py
2.1.4 上传代码,requirements.txt还有Dockerfile到linux服务器
pwd
/opt/tmp/docker_py_test1
tree
├── app
│ ├── app.py
│ └── requirements.txt
└── Dockerfile
1 directory, 3 files
tree命令默认linux是没有的需要自己安装,安装命令 yum -y install tree
2.2 执行构建命令
docker build -t app:hello .
Sending build context to Docker daemon 4.096 kB
Step 1/5 : FROM python:3.7
Trying to pull repository docker.io/library/python ...
3.7: Pulling from docker.io/library/python
b9a857cbf04d: Pull complete
d557ee20540b: Pull complete
3b9ca4f00c2e: Pull complete
667fd949ed93: Pull complete
4ad46e8a18e5: Pull complete
381aea9d4031: Pull complete
8859f1a219bb: Pull complete
94db86aad80b: Pull complete
c1bc6529ce9f: Pull complete
Digest: sha256:b06f909bae1709bb370ef3d1b05d3165f7b20adbc457f512904ce0df0b01f378
Status: Downloaded newer image for docker.io/python:3.7
---> ca194d6afe58
Step 2/5 : WORKDIR /opt
---> 4e0dd04cd380
Removing intermediate container a9694c289a37
Step 3/5 : ADD . /opt
---> 4ac7a3482272
Removing intermediate container 04cce5102f2d
Step 4/5 : RUN pip install -r /opt/app/requirements.txt
---> Running in fcd349077812
---> f58cbf777ba1
Removing intermediate container fcd349077812
Step 5/5 : CMD python /opt/app/app.py
---> Running in 3ff966ac1b3c
---> a4f114a8be3a
Removing intermediate container 3ff966ac1b3c
Successfully built a4f114a8be3a
2.3 查看构建的镜像
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
app hello a4f114a8be3a About a minute ago 881 MB
app v1.0.0 2680ec4a21ab 4 hours ago 698 MB
可以看到已经构建好了名为app:hello的python程序镜像
2.4 根据构建的镜像创建容器
docker run app:hello
Helloworld
可以看到输出正常,至此python镜像制作已经完成