Editing Files from dockerfile - docker

I need to add several lines to /etc/sysctl.conf in a Docker image.
Is there an idempotent way to do this via a Dockerfile rather than editing manually and using the docker commit approach?

I would use the following approach in the Dockerfile
RUN echo "Some line to add to a file" >> /etc/sysctl.conf
That should do the trick. If you wish to replace some characters or similar you can work this out with sed by using e.g. the following:
RUN sed -i "s|some-original-string|the-new-string |g" /etc/sysctl.conf
However, if your problem lies in simply getting the settings to "bite" this question might be of help.

sed work pretty well to replace stuff, if you need to append, you can user double redirect
sed -i 's/origin text/new text/g' /etc/sysctl.conf
bash -c 'echo hello world' >> /etc/sysctl.conf
-i is a non-standard option of GNU sed for inline editing (alleviating the need for dealing with temporary files).
The s is the substitute command of sed for find and replace
The g means global replace i.e. find all occurrences of origin text and replace with new text using sed

Related

Docker file RUN multiple sed commands

I am trying to change several configuration items in a single file that is part of an existing Docker image using the following RUN command:
RUN sed --in-place '/start_rpc:/ s/false/true/g' /etc/cassandra/cassandra.yaml &&\
sed --in-place '/broadcast_rpc_address:/ s/172.17.0.2/192.168.1.248/g' /etc/cassandra/cassandra.yaml &&\
sed --in-place '/listen_address:/ s/172.17.0.2/192.168.1.248/g' /etc/cassandra/cassandra.yaml &&\
sed --in-place '/seeds:/ s/172.17.0.2/192.168.1.248/g' /etc/cassandra/cassandra.yaml
I am sure the multiple sed commands are fine as I can run them on the host's console and achieve the 4 changes I am trying to execute.
The docker build does not show any errors and, in fact, it generates a new image. However, when I run the container and login to it, I can see that only the first of the four replacements took place.
I have already tried several combinations, including a compound sed such as:
RUN sed --in-place '/start_rpc:/ s/false/true/g; /broadcast_rpc_address:/ s/172.17.0.2/192.168.1.248/g; /listen_address:/ s/172.17.0.2/192.168.1.248/g; /seeds:/ s/172.17.0.2/192.168.1.248/g' /etc/cassandra/cassandra.yaml
And also four individual RUN commands. In all cases the result was the same: start_rpc is changed to true but not one of the other IP addresses gets changed.
Does anyone have any idea what could be wrong here and, if so, why docker build does not report something useful (and preferably fails)?
The answer to these problems can be found here but, in a nutshell, once the container starts, additional scripts are run to complete the set up of Cassandra and IP addresses are the typical type of configuration that can only be discovered once the container starts.

Dockerfile ENV not replacing in sed

I have set up dockerfile with making changes to config files with sed.
The image is a simple rtmp restreamer.
The lines in dockerfile go like:
RUN sed -i 's/ytkey/${YOUTUBE_KEY}/g' /etc/nginx/nginx.conf &&\
sed -i 's/fbkey/${FACEBOOK_KEY}/g' /etc/nginx/nginx.conf
i set up ENV at the beginning
ENV YOUTUBE_KEY=default FACEBOOK_KEY=default
but after building the image it doesn't replace ytkey or fbkey as default but inputs a string ${YOUTUBE_KEY}.
I have tried running
RUN sed -i 's/ytkey/\${YOUTUBE_KEY}/g' /etc/nginx/nginx.conf &&\
sed -i 's/fbkey/\${FACEBOOK_KEY}/g' /etc/nginx/nginx.conf
But had the same result. Is it a problem with sed (having the env in '') or something else? Is there an alternative to sed that works with dockerfile?
Or maybe i'm doing things completely the wrong way?
You can use double quotation marks around environment variables like this:
RUN sed -i 's/user/'"${YOUTUBE_KEY}"'/g' /etc/nginx/nginx.conf &&\
sed -i 's/pid/'"${FACEBOOK_KEY}"'/g' /etc/nginx/nginx.conf
I realise the question is specifically about sed, but you might also consider using envsubst to do this, especially if you start to use more variables.
It processes stdin to stdout, so in your example you would need to use a temp file strategy, but personally I prefer that approach:
envsubst < /etc/nginx/nginx.conf > /etc/nginx/nginx.conf.tmp
mv /etc/nginx/nginx.conf.tmp /etc/nginx/nginx.conf
For more complex configs, your templates would often be in a different directory anyway, so this wouldn't be necessary.

How to Search for a number and replace it with other number

I have a file server.xml with below line-
Server port="8007" shutdown="SHUTDOWN"
I want to search for 8007 and replace it with other number eg.: 8010.
How can I do it?
try this :
sed 's/8007/8010/g' yourfile
To make replacements you can use sed. I suppose that the new "port" is stored in a variable. As a result both solutions bellow works ok with GNU Sed:
$ a=$'Server port="8007" shutdown="SHUTDOWN"';echo "$a"
Server port="8007" shutdown="SHUTDOWN"
$ newport="8010"
$ sed -r "s/([0-9]+)/$newport/g" <<<"$a"
Server port="8010" shutdown="SHUTDOWN"
# Alternative:
$ sed -r 's/(port=")(.*)(" .*)/\1'"$newport"'\3/g' <<<"$a"
sed -r (or sed -E) enables extended regex groups.
If you need to apply replacements in-place (on the file) you need to use also -i switch in sed (sed -r -i.bak "....")

Why does this grep -F not work?

I've used grep -F extensively at work (CentOS) to ignore regex pattern in the match. Now here's what I'm trying at home (Ubuntu 14.04):
$ cat file
Here is
the -F
you were looking
for!
~$ grep -F '-F' file
_
The underscore is meant to show a blinking cursor, as if it's waiting for input. Could it be because Ubuntu's grep doesn't follow all POSIX switches (I read that -F was specified by POSIX) or am I making a mistake somewhere?'
===== Update ======
Interestingly, it fails only when there's a newline following -F. If you change the text to, say, -F option, then the line matches. A bug in grep?
Specifying the same argument twice has no effect, so
grep -F '-F' file
is the same as grep -F file, which of course searches for the fixed-string file in its standard input.
The single-quotes are a red-herring. They protect the -F from any expansion by the shell (like glob-expansion, variable expansion, command substitution, etc.), and are removed by the shell before grep sees the -F.
What you need to do is use grep's -e pattern argument:
grep -F -e '-F' file
Given that context, the -F will be interpreted as the pattern. The single-quotes are still redundant. You could single-quote every other arg. I left them in because it helps humans come to the right conclusion at first glance, and it's generally not bad practice to quote stuff that could contain shell meta-characters in a future version of the script, even if it's currently safe.

Why is capistrano interpreting a flag passed with a command to `run` as input?

I'm trying to do this:
run "echo -n 'foo' > bar.txt"
and the contents of bar.txt ends up being:
-n foo \n
(With \n representing an actual newline)
I use run for other commands like rm -rf and, to my knowledge, it works fine.
I just found this in man echo:
Some shells may provide a builtin echo command which is similar or identical to this utility. Most notably, the builtin echo in sh(1) does not accept the -n option. Consult the builtin(1) manual page.
My version of bash has an echo builtin but seems to be respecting the -n flag. It looks like the shell on your deployment machine doesn't, in which case using the full path to the echo binary might do what you want here:
run "/bin/echo -n 'foo' > bar.txt"
It appears as though the -n flag isn't being interpreted as a flag by the shell. If, from the command line, one executes echo -Y hi, the output will be -Y hi.

Resources