Nowadays, two of the biggest trends in application development have been the rise of serverless and containerization. This year, Google announced a new product called Cloud Run that is designed to bring the two together. At the same time, Google also announced Cloud Run for GKE which is specifically designed to run on Google’s version of Kubernetes. Likewise, I develop some of my applications and I refer them to survive on Cloud Run. I assume you have a Symfony 4 application as well. Let's start.
First of all, you need to read the container runtime contract page. There are some standards to follow the ways for Cloud Run.
https://cloud.google.com/run/docs/reference/container-contract
The crucial thing is that your application is supposed to listen 8080 port for now. It's the beta and in the future, this situation might be changed. Therefore, I've created an Nginx conf to listen to 8080.
server {
listen 8080;
server_name localhost;
root /usr/share/nginx/html/public;
location / {
try_files $uri /index.php$is_args$args;
}
location ~ ^/index\.php(/|$) {
fastcgi_pass unix:/run/php-fpm7.2/php-fpm.sock;
#fastcgi_pass 127.0.0.1:9000;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
internal;
}
location ~ \.php$ {
return 404;
}
error_log /var/log/nginx/project_error.log;
access_log /var/log/nginx/project_access.log;
}
Also, I've created a Docker file to handle container issues.
FROM phpearth/php:7.2-nginx
COPY . /usr/share/nginx/html
COPY default.conf /etc/nginx/conf.d/default.conf
COPY php-fpm.conf /etc/php/7.2/php-fpm.d/www.conf
COPY php.ini /etc/php.ini
RUN apk add --no-cache composer
WORKDIR /usr/share/nginx/html
RUN mkdir -p /run/nginx && chown -R nginx:nginx /run/nginx && chown -R nginx:nginx /usr/share/nginx/html \
&& composer install -vvv \
&& mkdir -p /usr/share/nginx/html/var && chmod -R 777 /usr/share/nginx/html/var \
&& chown -R nginx:nginx /usr/share/nginx/html/var
I've created my own php.ini file.
[PHP]
engine = On
short_open_tag = On
precision = 14
output_buffering = Off
zlib.output_compression = Off
implicit_flush = Off
unserialize_callback_func =
serialize_precision = 100
disable_functions = dl
disable_classes =
zend.enable_gc = On
expose_php = Off
max_execution_time = 30
max_input_time = 60
memory_limit = 512M
error_reporting = E_ALL & ~E_NOTICE
display_errors = On
display_startup_errors = Off
log_errors = On
log_errors_max_len = 1024
ignore_repeated_errors = Off
ignore_repeated_source = Off
report_memleaks = On
track_errors = Off
html_errors = On
error_log = error_l
variables_order = "EGPCS"
request_order = "GP"
register_argc_argv = On
auto_globals_jit = On
post_max_size = 64M
auto_prepend_file =
auto_append_file =
default_mimetype = "text/html"
default_charset = "UTF-8"
include_path = ".:/opt/php72/lib/php"
doc_root =
user_dir =
enable_dl = Off
file_uploads = On
upload_max_filesize = 64M
max_file_uploads = 20
allow_url_fopen = On
allow_url_include = On
default_socket_timeout
cli_server.color
date.timezone = Asia/Riyadh
pdo_mysql.cache_size = 2000
pdo_mysql.default_soc
sendmail_path = /usr/sbin/sendmail -t
mail.add_x_header
sql.safe_mode =
odbc.allow_persistent = Off
odbc.check_persistent = Off
odbc.max_persistent = -1
odbc.max_links = -1
odbc.defaultlrl = 4096
odbc.defaultbinmode
ibase.allow_persistent = 1
ibase.max_persistent = -1
ibase.max_links = -1
ibase.timestampformat = "%Y-%m-%d %H:%M:%S"
ibase.dateformat = "%Y-%m-%d"
ibase.timeformat = "%H:%M"
mysqli.max_persistent = -1
mysqli.allow_persistent = Off
mysqli.max_links = -1
mysqli.cache_size = 2000
mysqli.default_port = 3306
mysqli.default_socket =
mysqli.default_host =
mysqli.default_user =
mysqli.default_pw =
mysqli.reconnect =
mysqlnd.collect_statistics = Off
mysqlnd.collect_memory_statistics =
pgsql.allow_persistent = Off
pgsql.auto_reset_persistent = Off
pgsql.max_persistent = -1
pgsql.max_links = -1
pgsql.ignore_notice = 0
pgsql.log_notice
bcmath.scale
session.save_handler = files
session.save_path = "/tmp"
session.use_strict_mode = 0
session.use_cookies = 1
session.use_only_cookies = 1
session.name = PHPSESSID
session.auto_start = 0
session.cookie_lifetime = 0
session.cookie_path = /
session.cookie_domain =
session.cookie_httponly =
session.serialize_handler = php
session.gc_probability = 1
session.gc_divisor = 100
session.gc_maxlifetime = 1440
session.referer_check =
session.cache_limiter = nocache
session.cache_expire = 180
session.use_trans_sid = 0
session.hash_function = 0
session.hash_bits_per_character = 5
url_rewriter.tags = "a=href,area=href,frame=src,input=src,form=,fields"
zend.assertions
tidy.clean_output =
soap.wsdl_cache_enabled=1
soap.wsdl_cache_dir="/tmp"
soap.wsdl_cache_ttl=86400
soap.wsdl_cache_limit
ldap.max_links
And, we need to create a php-fpm.conf to figure out the PHP workers.
[www]
user = www-data
group = www-data
listen = /run/php-fpm7.2/php-fpm.sock
listen.owner = nginx
listen.group = nginx
listen.mode = 0660
pm = static
pm.start_servers = 1
pm.max_children = 5
pm.min_spare_servers = 1
pm.max_spare_servers = 5
You are going to have this structure in the end.
At this point, we need to create a Docker image into Google Cloud in the Container Registry service. Therefore, we run the following command.
gcloud builds submit --tag gcr.io/[Google-Cloud-Project]/[Image-Name]:[Version]
After creating the image, we will able to use that image like this.
gcloud beta run deploy [Service-Name] --image gcr.io/[Google-Cloud-Project]/[Image-Name]:[Version] --region europe-west1 --platform managed
By running this command, we push our earlier image to create a container on Cloud Run. When you look over the Google Cloud dashboard, you are going to reach all of the details about your service.
As you can recall, we have learned to automate this process the following post.
https://dev.to/_mertsimsek/continuously-build-test-and-deploy-with-symfony-on-google-cloud-5a6i
You also change like this the cloudbuild.yaml file to get autonomous for Cloud Run.
steps:
# build the container image
- name: 'gcr.io/cloud-builders/docker'
args: ['build', '-t', 'gcr.io/$PROJECT_ID/[Service-Name]', '.']
# push the container image to Container Registry
- name: 'gcr.io/cloud-builders/docker'
args: ['push', 'gcr.io/$PROJECT_ID/[Service-Name]']
# Deploy container image to Cloud Run
- name: 'gcr.io/cloud-builders/gcloud'
args: ['beta', 'run', 'deploy', '[Service-Name]', '--image', 'gcr.io/$PROJECT_ID/[Service-Name]', '--region', 'europe-west1', '--platform', 'managed']
images:
- gcr.io/$PROJECT_ID/[Service-Name]
Conclusion
Google wants us to focus only on our codes. Each Cloud Run service has a unique endpoint and auto-scales deployed containers. Therefore, we don't need to suffer about the rest of the code. I hope, I succeed to change your ideas about to survive on Google Cloud platform.
Top comments (3)
Since you tried it, how much does it cost when you don't use it at all for a month for example ? Is it able to scale down to 0 so that it's free or almost free during the initial development of the application for example, when there is only a single user not very active on the prod environment ?
yes, definitely it would be a pretty cool solution.
chown: invalid user: 'nginx:nginx'