Docker
安装
卸载旧版本
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-selinux \
docker-engine-selinux \
docker-engine
安装依赖
yum install -y yum-utils device-mapper-persistent-data lvm2
安装新版本
// 国内源安装
yum-config-manager --add-repo https://mirrors.ustc.edu.cn/docker-ce/linux/centos/docker-ce.repo
// 官方源安装
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
// 安装
yum-config-manager --enable docker-ce-edge
yum makecache fast
yum install docker-ce
启动
systemctl enable docker
systemctl start docker
添加内核配置参数
tee -a /etc/sysctl.conf <<-EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
重新加载配置
sysctl -p
安装自定义镜像
创建一个基于 centos7 的 ngxin 服务的镜像:
搜索基础镜像
docker search centos
结果:
结果:
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
centos The official build of CentOS. 3522 [OK]
jdeathe/centos-ssh CentOS-6 6.9 x86_64 / CentOS-7 7.3.1611 x8... 78 [OK]
tutum/centos Simple CentOS docker image with SSH access 33
kinogmt/centos-ssh CentOS with SSH 15 [OK]
centos/postgresql-94-centos7 PostgreSQL 9.4 SQL database server 11
我们可以用最基础的: centos ,然后自己在该镜像基础上再安装额外的环境。
下载镜像
docker pull centos:latest // 或者 docker pull centos:centos7
冒号后面是要安装的版本,这个可以在 Docker Hub 上看到: https://hub.docker.com/_/centos/
在国内服务器上安装的时候非常缓慢,直接使用阿里云的镜像。如果 Docker客户端版本大于1.10:
mkdir -p /etc/docker
tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://apdv9k7p.mirror.aliyuncs.com"]
}
EOF
systemctl daemon-reload
systemctl restart docker
然后再下载镜像。
查看当前镜像
docker images
结果:
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos centos7 e934aafc2206 3 weeks ago 195MB
创建自定义镜像
我们可以先创建一个空的容器,然后连接进去再一步下不安装。也可以通过配置文件来定义规则让它自动安装。
创建一个新的镜像,标签是 nginx,然后用它创建一个容器:
docker tag e934aafc2206 centos7:nginx
docker run -t -i centos7:nginx /bin/bash
可以通过 docker ps -a
查看容器。也可以通过 docker rm [容器名称或ID]
删除容器。创建完成后,通过 docker start [容器名称或ID]
来启动,docker stop [容器名称或ID]
关闭容器。
启动后,可以通过
docker exec -it [容器名称或ID] bash
进入容器的控制台。在控制台安装完环境后,可能通过
docker export 7691a814370e > centos-nginx.tar
建立容器的快照。后面,可以通过
cat centos-nginx.tar | docker import - centos/nginx:v1.0
导入为镜像除了容器快照的方式,还可以直接把变更添加到镜像上:
docker commit -a "SunYu" -m "安装 nginx" [容器名称] nginx:v1
创建好后可以通过
docker run --name web -d -p 80:80 nginx:v1
运行容器。并进行端口映射以及容器的命名。
要注意的是,commit 方式产生的镜像文件特别大。
自定义安装是通过 Dockerfile 定义的。先创建一个工作目录,如:/data/soft/docker, 在该目录下先下载安装文件: wget http://nginx.org/download/nginx-1.12.2.tar.gz
再创建 nginx 的服务控制文件 nginx:
#!/bin/bash
# nginx Startup script for the Nginx HTTP Server
# it is v.0.0.2 version.
# chkconfig: - 85 15
# description: Nginx is a high-performance web and proxy server.
# It has a lot of features, but it's not for everyone.
# processname: nginx
# pidfile: /usr/local/webserver/nginx/logs/nginx.pid
# config: /usr/local/webserver/nginx/conf/nginx.conf
nginxd=/usr/local/webserver/nginx/sbin/nginx
nginx_config=/usr/local/webserver/nginx/conf/nginx.conf
nginx_pid=/usr/local/webserver/nginx/logs/nginx.pid
RETVAL=0
prog="nginx"
# Source function library.
. /etc/rc.d/init.d/functions
# Source networking configuration.
. /etc/sysconfig/network
# Check that networking is up.
[ ${NETWORKING} = "no" ] && exit 0
[ -x $nginxd ] || exit 0
# Start nginx daemons functions.
start() {
if [ -e $nginx_pid ];then
echo "nginx already running...."
exit 1
fi
echo -n $"Starting $prog: "
daemon $nginxd -c ${nginx_config}
RETVAL=$?
echo
[ $RETVAL = 0 ] && touch /var/lock/subsys/nginx
return $RETVAL
}
# Stop nginx daemons functions.
stop() {
echo -n $"Stopping $prog: "
killproc $nginxd
RETVAL=$?
echo
[ $RETVAL = 0 ] && rm -f /var/lock/subsys/nginx /var/run/nginx.pid
}
# reload nginx service functions.
reload() {
echo -n $"Reloading $prog: "
#kill -HUP `cat ${nginx_pid}`
killproc $nginxd -HUP
RETVAL=$?
echo
}
# See how we were called.
case "$1" in
start)
start
;;
stop)
stop
;;
reload)
reload
;;
restart)
stop
start
;;
status)
status $prog
RETVAL=$?
;;
*)
echo $"Usage: $prog {start|stop|restart|reload|status|help}"
exit 1
esac
exit $RETVAL
然后再创建配置文件 Dockerfile:
FROM centos7:nginx
RUN mkdir -p /data/soft/
ADD nginx /etc/init.d/
ADD nginx-1.12.2.tar.gz /data/soft/
RUN yum -y install gcc gcc-c++ autoconf libjpeg libjpeg-devel libpng libpng-devel freetype freetype-devel libxml2 libxml2-devel zlib zlib-devel glibc glibc-devel glib2 glib2-devel bzip2 bzip2-devel curl curl-devel e2fsprogs e2fsprogs-devel openssl openssl-devel openldap openldap-devel nss_ldap openldap-clients openldap-servers python-devel libicu-devel chrpath nspr-devel readline-devel ncurses-devel boost boost-devel pcre-devel js-devel git tcsh js js-devel libevent libevent-devel subversion git-core tcsh tcl net-tools net-snmp net-snmp-devel net-snmp-utils cmake postgresql-devel libxslt-devel && \
/usr/sbin/groupadd -f www && \
/usr/sbin/useradd -s /sbin/nologin -g www www && \
mkdir -p /usr/local/webserver/nginx
RUN cd /data/soft/nginx-1.12.2 && \
./configure --user=www --group=www --prefix=/usr/local/webserver/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_gzip_static_module --with-pcre && \
make && make install && \
chmod a+x /etc/init.d/nginx && \
chkconfig --add nginx && \
chkconfig nginx --level 2345 on
CMD ["/usr/local/webserver/nginx/sbin/nginx", "-g", "daemon off;"]
EXPOSE 80
创建容器:
docker build -t centos7:nginx .
通过 ADD 方式将本地的文件添加容器中。而且它会自动把压缩文件解压。所以上面的配置文件中,直接用了 cd /data/soft/nginx-1.12.2。而没有进行解压处理。
通过 CMD 命令,我们让 nginx 启动。并在前台运行。对于容器而言,其启动程序就是容器应用进程,容器就是为了主进程而存在的,主进程退出,容器就失去了存在的意义,从而退出。所以要把 nginx 在前台运行。要不然我们开启容器后它会马上自动退出。
然后,通过 EXPOSE 80 将容器的 80 端口暴露出来。后面我们可以将宿主机器的 80 端口和它进行映射。这样就可以通过访问主机的 80 和容器连通了。
启动容器
创建完后,创建新容器:
docker run --name web -d -p 80:80 centos7:nginx
创建完后,可能在 docker ps -a
的结果里查看。同时,docker stop [容器名称或ID]
可以关闭,docker start [名称或ID]
可以启动已经存在且已经关闭的容器。
通过 docker exec -it web bash
可以连接到容器的控制台,在这里直接 exit 可以退出控制台但不会关闭容器。
这时候查看主机的端口,发现 80 端口已经开启了。但直接访问 http://[IP] 是没内容的。因为我们的容器里的 WEB 服务里还是空的。我们可以把项目放在主机上,通过目录映射到容器中。如: 在当前目录下创建 testproject 目录,里面创建一个 index.html 内容是 123。
我们关闭容器,重新创建容器。
docker stop web
docker rm web
docker run --name web -d -p 80:80 -v /data/soft/docker/testproject/:/usr/local/webserver/nginx/html centos7:nginx
这样就进行了目录的绑定。而且,在主机上改了文件后,容器中会自动同步。这时候访问 http://[借主IP] 就可以看到内容了。
但是,目前为止我们只能访问静态文件。容器里并没有安装PHP,MYSQL等。所以无法完整的支撑起一个项目。我们当然可以把这些全部安装到一个容器里,但为了灵活。我们也可以分别安装在不同的容器。
容器间的互联,可以建立一个自有的网络,然后进行通信。但更好的方案是用 Docker compose。
Docker Compose
使用该工具,可以快速的部署分布式应用。它的定位是:定义和运行多个 Docker 容器的应用。
通过 compose,我们可以把独立的一组容器进行关联。它通过配置文件:docker-compose.yml 进行配置。它有两个重要概念:
- 服务 (service):一个应用的容器,实际上可以包括若干运行相同镜像的容器实例。
- 项目 (project):由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义。
一个项目可以由多个服务(容器)关联而成,Compose 面向项目进行管理。
安装
curl -L https://raw.githubusercontent.com/docker/compose/1.8.0/contrib/completion/bash/docker-compose > /etc/bash_completion.d/docker-compose
卸载
rm /usr/local/bin/docker-compose
简单示例
新建一个工作目录。如:/data/soft/docker/compose
,进入目录
创建 app.py
from flask import Flask
from redis import Redis
app = Flask(__name__)
redis = Redis(host='redis', port=6379)
@app.route('/')
def hello():
count = redis.incr('hits')
return 'Hello World! 该页面已被访问 {} 次。\n'.format(count)
if __name__ == "__main__":
app.run(host="0.0.0.0", debug=True)
创建 Dockerfile
FROM python:3.6-alpine
ADD . /code
WORKDIR /code
RUN pip install redis flask
CMD ["python", "app.py"]
创建 docker-compose.yml
version: '3'
services:
web:
build: .
ports:
- "80:5000"
redis:
image: "redis:alpine"
运行 compose 项目
$ docker-compose up
这时候,访问 http://[宿主IP]/ 可以看到,每次刷新后,计数都会 +1。
这里就是用 Compose 来控制容器了,包括了端口映射等,而且它会创建两个容器。
命令说明
docker-compose build
构建(重新构建)项目中的服务容器。
docker-compose config
验证 Compose 文件格式是否正确,若正确则显示配置,若格式错误显示错误原因。
docker-compose down
停止 up 命令所启动的容器,并移除网络
docker-compose exec
进入指定的容器。
docker-compose images
列出 Compose 文件中包含的镜像。
docker-compose ps
列出项目中目前的所有容器。
docker-compose restart
重启项目中的服务。
docker-compose rm
删除所有(停止状态的)服务容器。先执行 docker-compose stop 命令来停止容器。
-f, –force 强制直接删除,包括非停止状态的容器。-v 删除容器所挂载的数据卷。
docker-compose start
启动已经存在的服务容器。
docker-compose stop
停止已经处于运行状态的容器,但不删除它。通过 docker-compose start 可以再次启动这些容器。
docker-compose up
该命令十分强大,它将尝试自动完成包括构建镜像,(重新)创建服务,启动服务,并关联服务相关容器的一系列操作。
链接的服务都将会被自动启动,除非已经处于运行状态。
可以说,大部分时候都可以直接通过该命令来启动一个项目。
默认情况,docker-compose up
启动的容器都在前台,控制台将会同时打印所有容器的输出信息,可以很方便进行调试。
当通过 Ctrl-C
停止命令时,所有容器将会停止。
如果使用 docker-compose up -d
,将会在后台启动并运行所有的容器。一般推荐生产环境下使用该选项。
默认情况,如果服务容器已经存在,docker-compose up
将会尝试停止容器,然后重新创建(保持使用 volumes-from 挂载的卷),以保证新启动的服务匹配 docker-compose.yml
文件的最新内容。如果用户不希望容器被停止并重新创建,可以使用 docker-compose up --no-recreate
。这样将只会启动处于停止状态的容器,而忽略已经运行的服务。如果用户只想重新部署某个服务,可以使用 docker-compose up --no-deps -d <SERVICE_NAME>
来重新创建服务并后台停止旧服务,启动新服务,并不会影响到其所依赖的服务。
模板文件
模板文件是使用 Compose 的核心,涉及到的指令关键字也比较多。这里面大部分指令跟 docker run 相关参数的含义都是类似的。
默认的模板文件名称为 docker-compose.yml,格式为 YAML 格式。如:
version: "3"
services:
webapp:
image: examples/web
ports:
- "80:80"
volumes:
- "/data"
每个服务都必须通过 image 指令指定镜像或 build 指令(需要 Dockerfile)等来自动构建生成镜像。
如果使用 build 指令,在 Dockerfile 中设置的选项(例如:CMD, EXPOSE, VOLUME, ENV 等) 将会自动被获取,无需在 docker-compose.yml 中再次设置。
build
指定 Dockerfile 所在文件夹的路径(可以是绝对路径,或者相对 docker-compose.yml 文件的路径)。 Compose 将会利用它自动构建这个镜像,然后使用这个镜像。如: build: ./dir
也可以使用 context 指令指定 Dockerfile 所在文件夹的路径。使用 dockerfile 指令指定 Dockerfile 文件名。使用 arg 指令指定构建镜像时的变量。如:
webapp:
build:
context: ./dir
dockerfile: Dockerfile-alternate
args:
buildno: 1
image
指定为镜像名称或镜像 ID。如果镜像在本地不存在,Compose 将会尝试拉取这个镜像。如:
image: ubuntu
image: orchardup/postgresql
image: a4bc65fd
command
覆盖容器启动后默认执行的命令。如: command: echo "hello world"
container_name
指定容器名称。默认将会使用 项目名称_服务名称_序号 这样的格式。自定义方式如:
container_name: docker-web-container
注意: 指定容器名称后,该服务将无法进行扩展(scale),因为 Docker 不允许多个容器具有相同的名称。
depends_on
解决容器的依赖、启动先后的问题。以下例子中会先启动 redis db 再启动 web
version: '3'
services:
web:
build: .
depends_on:
- db
- redis
redis:
image: redis
db:
image: postgres
注意:web 服务不会等待 redis, db 「完全启动」之后才启动。
environment 设置环境变量。可以使用数组或字典两种格式。
只给定名称的变量会自动获取运行 Compose 主机上对应变量的值,可以用来防止泄露不必要的数据。如:
environment:
RACK_ENV: development
SESSION_SECRET:
environment:
- RACK_ENV=development
- SESSION_SECRET
如果变量名称或者值中用到 true|false,yes|no 等表达 布尔 含义的词汇,最好放到引号里,避免 YAML 自动解析某些内容为对应的布尔语义。这些特定词汇,包括
y|Y|yes|Yes|YES|n|N|no|No|NO|true|True|TRUE|false|False|FALSE|on|On|ON|off|Off|OFF
expose
暴露端口,但不映射到宿主机,只被连接的服务访问。
ports
暴露端口信息。
使用宿主端口:容器端口 (HOST:CONTAINER) 格式,或者仅仅指定容器的端口(宿主将会随机选择端口)都可以。
ports:
- "3000"
- "8000:8000"
- "49100:22"
- "127.0.0.1:8001:8001"
注意:当使用 HOST:CONTAINER 格式来映射端口时,如果你使用的容器端口小于 60 并且没放到引号里,可能会得到错误结果,因为 YAML 会自动解析 xx:yy 这种数字格式为 60 进制。为避免出现这种问题,建议数字串都采用引号包括起来的字符串格式。
secrets
存储敏感数据,例如 mysql 服务密码。
version: "3"
services:
mysql:
image: mysql
environment:
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_password
secrets:
- db_root_password
- my_other_secret
secrets:
my_secret:
file: ./my_secret.txt
my_other_secret:
external: true
sysctls
配置容器内核参数。
sysctls:
net.core.somaxconn: 1024
net.ipv4.tcp_syncookies: 0
ulimits
指定容器的 ulimits 限制值。例如,指定最大进程数为 65535,指定文件句柄数为 20000(软限制,应用可以随时修改,不能超过硬限制) 和 40000(系统硬限制,只能 root 用户提高)。
ulimits:
nproc: 65535
nofile:
soft: 20000
hard: 40000
restart 指定容器退出后的重启策略为始终重启。该命令对保持服务始终运行十分有效,在生产环境中推荐配置为 always 或者 unless-stopped。
restart: always
volumes
数据卷所挂载路径设置。可以设置宿主机路径 (HOST:CONTAINER) 或加上访问模式 (HOST:CONTAINER:ro)。
该指令中路径支持相对路径。
volumes:
- /var/lib/mysql
- cache/:/tmp/cache
- ~/configs:/etc/configs/:ro
复杂示例
现在创建一个 nginx + mysql + php7 的项目环境。需要的容器有:MySQL, Nginx, Php (项目文件也放在这里)。由于 MySQL, Nginx 都有现成的镜像,但我们项目需要 php7,且需要 compose, npm 等工具,所以我们自己安装。
PHP安装定义
创建 Dockfile:
FROM centos:centos7
MAINTAINER SunYu sunvipyu@gmail.com
RUN yum -y install vim wget sendmail
RUN yum -y install libtool make automake autoconf nasm libpng-static
RUN yum -y install git
RUN git --version
# Install PHP 7.1 on CentOS
RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm \
&& rpm -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm
RUN yum install yum-utils
RUN yum-config-manager --enable remi-php71
RUN yum -y install php71w \
php71w-bcmath \
php71w-cli \
php71w-common \
php71w-curl \
php71w-fpm \
php71w-gd \
php71w-ldap \
php71w-imap \
php71w-intl \
php71w-mbstring \
php71w-mcrypt \
php71w-mysqlnd \
php71w-opcache \
php71w-pdo \
php71w-pear \
php71w-pecl-apcu \
php71w-pecl-imagick \
php71w-pgsql \
php71w-process \
php71w-pspell \
php71w-recode \
php71w-soap \
php71w-tidy \
php71w-xml
RUN php -v
# Prepare PHP environment
COPY config/php/php-fpm.conf /etc/php-fpm.conf
COPY config/php/www.conf /etc/php-fpm.d/www.conf
COPY config/php/php.ini /usr/local/etc/php/php.ini
# Install Composer
RUN curl -sS https://getcomposer.org/installer | php
RUN mv composer.phar /usr/bin/composer
RUN composer --version
# Install Node.js
RUN curl -sL https://rpm.nodesource.com/setup_7.x | bash -
RUN yum -y install nodejs
RUN yum list installed nodejs
RUN node -v
# Final update and clean up
RUN yum -y update
RUN yum clean all
# Define work directory
WORKDIR /var/www/my-project
# Expose ports
EXPOSE 9000
CMD ["php-fpm", "-F", "-O"]
这里,我们安装 php7.1 且安装 compose, node.js 等环境。并开放 9000 端口供 nginx 后面使用。
Compose 定义
docker-compose.yml
version: '2'
services:
mysql:
image: mysql:latest
volumes:
- "./data/db:/var/lib/mysql"
ports:
- "3306:3306"
restart: always
environment:
- MYSQL_ROOT_PASSWORD=secret
- MYSQL_DATABASE=laravel_boilerplate
- MYSQL_USER=root
- MYSQL_PASSWORD=secret
project-env:
build: ./dockerfiles
depends_on:
- mysql
volumes:
- "/data/soft/my-project:/var/www/my-project"
- "./dockerfiles/config/php/php-fpm.conf:/etc/php-fpm.conf"
- "./dockerfiles/config/php/www.conf:/etc/php-fpm.d/www.conf"
- "./dockerfiles/config/php/php.ini:/usr/local/etc/php/php.ini"
nginx:
image: nginx:latest
depends_on:
- project-env
volumes:
- "/data/soft/my-project:/var/www/my-project"
- "./dockerfiles/config/nginx/default.conf:/etc/nginx/conf.d/default.conf"
ports:
- "80:80"
restart: always
模板定义中,创建了 mysql, nginx 两个新容器。并通过 Dockfile 创建项目容器 project-env,并把本地的一些配置文件上传,作为容器里的配置文件,配置文件内容有:
php-fpm.conf
[global]
error_log = /proc/self/fd/2
process.max = 128
systemd_interval = 0
include=/etc/php-fpm.d/*.conf
www.conf
[www]
user = apache
group = apache
listen = 9000
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.status_path = /status
ping.path = /ping
slowlog = /proc/self/fd/2
request_slowlog_timeout = 60s
chdir = /var/www
catch_workers_output = yes
env[HOSTNAME] = $HOSTNAME
env[PATH] = /usr/local/bin:/usr/bin:/bin
env[HOME] = /var/www
env[TMP] = /tmp
env[TMPDIR] = /tmp
env[TEMP] = /tmp
php_admin_value[date.timezone] = UTC
php_value[session.save_handler] = files
php_value[session.save_path] = /var/lib/php/session
php_value[soap.wsdl_cache_dir] = /var/lib/php/wsdlcache
php.ini
# Custom PHP settings
upload_max_filesize = 100M
post_max_size = 100M
memory_limit = 512M
max_execution_time = 180
default.conf
# Enable Gzip
gzip on;
gzip_http_version 1.0;
gzip_comp_level 2;
gzip_min_length 1100;
gzip_buffers 4 8k;
gzip_proxied any;
gzip_types
# text/html is always compressed by HttpGzipModule
text/css
text/javascript
text/xml
text/plain
text/x-component
application/javascript
application/json
application/xml
application/rss+xml
font/truetype
font/opentype
application/vnd.ms-fontobject
image/svg+xml;
gzip_static on;
gzip_proxied expired no-cache no-store private auth;
gzip_disable "MSIE [1-6]\.";
gzip_vary on;
# Expires map
map $sent_http_content_type $expires {
default off;
application/json off;
text/html 1h;
text/css max;
application/javascript max;
application/octet-stream max;
~image/ 1d;
~img/ 1d;
}
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
server_name localhost;
root /var/www/my-project;
index index.php index.html index.htm;
charset utf-8;
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
access_log /var/log/nginx/access.log combined;
error_log /var/log/nginx/error.log error;
expires $expires;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# This block will catch static file requests, such as images, css, js
# The ?: prefix is a 'non-capturing' mark, meaning we do not require
# the pattern to be captured into $1 which should help improve performance
location ~* \.(?:ico|css|js|gif|jpe?g|png|woff|woff2|ttf|html)$ {
# Some basic cache-control for static files to be sent to the browser
add_header Pragma public;
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
}
location ~ \.php$ {
try_files $uri /index.php =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass project-env:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.ht {
deny all;
}
client_max_body_size 100m;
}
nginx 的配置中,将 php 的请求转到了 project-env 去处理。
启动各容器
docker-compose -f docker-compose.yml up -d
执行一些自定义任务
项目可能会需要进行一些初始化。比如 php composer 的安装或者 npm 包的安装等。我们可以定义一个 sh 文件:
project-build.sh
#!/bin/bash
# Install dependencies
composer install --prefer-dist --no-interaction
# Install dependencies
npm install
npm run dev
然后执行:
docker exec project-env_1 ./dockerfiles/bin/prj-build.sh
这里的 project-env_1
是想要执行任务容器名称。可以通过 ps -a
查看。