Docker Volume Mounting issues with Ruby - ruby

I have a testcase where I am running an instance of Ruby inside a windows docker container. I should stress the ruby script works fine outside of docker. When run inside the docker container the script also works fine, except when the target of the Ruby file's access is on a mounted volume. In which case I get an error. I can for the testcase of course work around this issue by copying the file, but that would cause complications for the real script that found this problem.
Here's an example transcript, cbh_test is the mounted volume
PS C:\> echo ""> bob
PS C:\> cp cbh_test\failer.rb .
PS C:\> C:\Ruby25-x64\bin\ruby.exe .\failer.rb
PS C:\> cd cbh_test
PS C:\cbh_test> echo ""> bob
PS C:\cbh_test> C:\Ruby25-x64\bin\ruby.exe .\failer.rb
Traceback (most recent call last):
./failer.rb: Invalid argument # rb_readlink - C:/cbh_test (Errno::EINVAL)
Docker instance invoked by:
docker run -it -v c:\Users\me\work\fred:c:\cbh_test bob/failer powershell
Dockerfile:
# escape=`
FROM microsoft/windowsservercore:ltsc2016
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
COPY install_ruby.ps1 c:
RUN powershell c:\install_ruby.ps1
failer.rb:
def main(args)
fragment = "bob"
$tmp = File.open(File.join(File.dirname(__FILE__), fragment), 'r+').read
end
main($ARGV)
install_ruby.ps:
$RUBY_VERSION = "2.5.3-1"
$RUBY_RELEASE = "2.5.3-1"
$url = ('https://github.com/oneclick/rubyinstaller2/releases/download/rubyinstaller-{0}/rubyinstaller-{1}-x64.exe'-f $RUBY_VERSION, $RUBY_RELEASE);
$exe = "ruby-install.exe"
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;
Invoke-WebRequest -Uri $url -OutFile $exe;
$args = "/silent /tasks='assocfiles,modpath'"
Start-Process -FilePath $exe -ArgumentList $args -PassThru -Wait

I tried for several days and the only solution I was able to find to this problem was to use ltsc2019.

Related

Can't execute AWS CLI command with user_data in Terraform

I am using Terraform to spin up an EC2-instance where I have defined some user_data. In the user_data I download AWS CLI and set up the config file and credentials file. I then want to grab a file from my s3 bucket. This is what I've written so far:
data "template_file" "scripts" {
template = <<EOF
<powershell>
$dlurl = "installpathtoawscli.msi"
$installerPath = Join-Path $env:TEMP (Split-Path $dlurl -Leaf)
Invoke-WebRequest $dlurl -OutFile $installerPath
Start-Process -FilePath msiexec -Args "/i $installerPath /passive" -Verb RunAs -Wait
mkdir C:\temp
New-Item -Name 'b.bat' -Path 'C:\temp' -Value 'aws s3 cp s3://mybucketname/myfile.extension C:\temp\extension > C:\temp\test.txt'
New-Item -Name 'a.bat' -Path 'C:\Users\Administrator' -Value 'mkdir C:\Users\Administrator\.aws
echo [default]>> C:\Users\Administrator\.aws\credentials
echo aws_access_key_id = MY_ACCESS_KEY>> C:\Users\Administrator\.aws\credentials
echo aws_secret_access_key = MY_SECRET_KEY>> C:\Users\Administrator\.aws\credentials
echo [default]>> C:\Users\Administrator\.aws\config
echo region = MY_REGION>> C:\Users\Administrator\.aws\config
echo output = MY_OUTPUT>> C:\Users\Administrator\.aws\config'
C:\Users\Administrator\a.bat
C:\temp\b.bat
</powershell>
EOF
}
b.bat is executed and a txt file is created, however, it is empty and no file is grabbed from the s3 bucket. If I try to execute it manually (by RDPing to the instance) it grabs the file. Any ideas why this is happening?
I found the solution after several days of trying.
The AWS.exe location was not being registered in the PATH environment yet. Restarting the command prompt would do the trick, however, Terraform can't do this, thus explaining why it worked when I did it manually.
I had to provide the full path for AWS.exe in order to make it work e.g. C:\Program Files\Amazon\AWSCLI\bin\aws.exe or C:\Program Files\Amazon\AWSCLIV2\aws.exe depending on the version of AWS CLI.

How to update path in Windows container for Docker?

I am trying to update the path inside my container. I have been everywhere and checked out several threads on this and nothing works. So, that's the trick?
# escape=`
ARG SDK_VERSION=4.8
FROM mcr.microsoft.com/dotnet/framework/sdk:${SDK_VERSION}
ENV NODE_VERSION=8.11.2
HEALTHCHECK NONE
RUN Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object
System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
USER ContainerAdministrator
RUN setx /M PATH "%PATH%;C:/Foo/bin"
USER ContainerUser
SHELL ["cmd", "/S", "/C"]
CMD ["powershell.exe", "-NoLogo", "-ExecutionPolicy", "Bypass"]
This is the error:
PS C:\users\cbongiorno\source> docker build -t mercury:latest -m 4GB -f Dockerfile i18n-tools
Sending build context to Docker daemon 2.057MB
Step 1/10 : ARG SDK_VERSION=4.8
Step 2/10 : FROM mcr.microsoft.com/dotnet/framework/sdk:${SDK_VERSION}
---> 4a9d58026a2d
Step 7/10 : RUN setx /M PATH "%PATH%;C:/Foo/bin"
---> Running in 1caf9e758af2
SUCCESS: Specified value was saved.
C:/Foo/bin : The term 'C:/Foo/bin' is not recognized as the name of a cmdlet,
function, script file, or operable program. Check the spelling of the name, or
if a path was included, verify that the path is correct and try again.
At line:1 char:96
+ ... ogressPreference = 'SilentlyContinue'; setx /M PATH %PATH%;C:/Foo/bin
+ ~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:/Foo/bin:String) [], ParentCo
ntainsErrorRecordException
+ FullyQualifiedErrorId : CommandNotFoundException
The command 'powershell -Command $ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue'; setx /M PATH "%PATH%;C:/Foo/bin"' returned a non-zero code: 1
There are at least two ways to update the PATH:
Using setx as the earlier answer suggests and as is displayed in the golang's nanoserver-1809/Dockerfile. Notice the use of the USER instruction. The ContainerAdministrator must be used in order to set the system PATH:
# PATH isn't actually set in the Docker image, so we have to set it from within the container
USER ContainerAdministrator
RUN setx /m PATH "%GOPATH%\bin;C:\go\bin;%PATH%"
USER ContainerUser
# doing this first to share cache across versions more aggressively
Using Powershell as displayed in the golang's windowsservercore-ltsc2016/Dockerfile
RUN $newPath = ('{0}\bin;C:\go\bin;{1}' -f $env:GOPATH, $env:PATH); \
Write-Host ('Updating PATH: {0}' -f $newPath); \
[Environment]::SetEnvironmentVariable('PATH', $newPath, [EnvironmentVariableTarget]::Machine);
# doing this first to share cache across versions more aggressively
Both ways do work with recent Docker Desktop.
The ENV instruction is not going to work on Windows.
This is what I got working, but it doesn't seem ideal:
RUN setx /M PATH $($Env:PATH + ';C:\Foo\bin')

RUN powershell failing in docker build on windows 2019 server

I am running on Windows 2019 server.
I am getting an error whenever I invoke powershell from a dockerfile on docker build
Error is..
---> Running in 6efa29aa8a4a
The command 'powershell -Command DIR' returned a non-zero code: 3221226505
Dockerfile..
# escape=` (backtick)
FROM mcr.microsoft.com/windows/servercore:ltsc2019
RUN DIR
RUN ["powershell", "-Command", "DIR"]
COPY ./ app/
WORKDIR app
CMD [ "someapp", "somearg" ]
I have tried replacing cmd with powershell via
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
RUN DIR
and the results are the same.
Thanks
Try running a dockerfile more like
FROM mcr.microsoft.com/windows/servercore/iis
RUN powershell -NoProfile -Command Remove-Item -Recurse
C:\inetpub\wwwroot*
WORKDIR /inetpub/wwwroot
COPY . /inetpub/wwwroot
maybe you gotta move your COPY command after the WORKDIR ?
Try different things out
Check to make sure you have update KB4532691 installed on your build machine (and host). The newest image of ltsc2019 (20/2020) has issues without it.
See https://hub.docker.com/_/microsoft-windows-servercore and https://support.microsoft.com/en-us/help/4542617/you-might-encounter-issues-when-using-windows-server-containers-with-t for more info

How to install a specific KB update to a Windows Server 2016 Docker container

I have a Windows Server 2016 Docker container and I want to apply a specific KB update to it. I wonder how to do it programmatically?
Your Dockerfile could look like this:
FROM microsoft/windowsservercore:ltsc2016
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
RUN Invoke-WebRequest "KB_URL" -OutFile update.exe -UseBasicParsing ; \
Start-Process -FilePath 'update.exe' -ArgumentList '--quiet', '--norestart' -Wait ; \
Remove-Item .\update.exe

In Docker (for Windows) How can I add registry entries in bulk while building my image?

I'm using Docker for Windows and building the docker image with a Dockerfile like this:
FROM mydockerhublogin/win2k16-ruby:1.0
# Set the working directory to /app
WORKDIR /app
# Copy the current directory contents into the container at /app
ADD . /app
# Make port 80 available to the world outside this container
EXPOSE 80
# Define environment variable
ENV NAME World
RUN powershell -Command \
$ErrorActionPreference = 'Stop'; \
New-Item "HKLM:\Software\WOW6432Node\ExampleCom" -Force ; \
New-ItemProperty "HKLM:\Software\WOW6432Node\ExampleCom" -Name MenuLastUpdate -Value "test" -Force
RUN powershell -Command \
$ErrorActionPreference = 'Stop'; \
New-Item "HKLM:\Software\ExampleCom" -Force ; \
New-ItemProperty "HKLM:\Software\ExampleCom" -Name MenuLastUpdate -Value "test" -Force
# Run ruby script when the container launches
CMD ["C:/Ruby23-x64/bin/ruby.exe", "docker_ruby_test.rb"]
Note that I am adding some registry entries to the Windows registry which the code inside the container will access. While this method of adding registry entries is fine for a few entries, my requirement is to add dozens of entries required for my windows application. Is there a way to do this in a more concise manner?
Try creating a file for the your registry entry and copy that inside the container.
Then try running Invoke-Command -ScriptBlock {regedit /i /s C:\shared\settings.reg}
The following is the only way I could getting working using 4.8-windowsservercore-ltsc2019
COPY Registry/ChromeConfiguration.reg .
RUN reg import ChromeConfiguration.reg

Resources